30 Commits
Author SHA1 Message Date
Lucas RayanandClaude Sonnet 5.5 5a9fe676fc feat(i18n): Simplified Chinese (zh-CN), search answers per locale, fr/de/es data fixes
CI / Lint e auditorias (push) Successful in 1m10s
CI / Trivy (dependências e segredos) (push) Successful in 12s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m39s
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 18s
Release / Cria a release no Gitea (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 23:28:39 -03:00
Lucas Rayan ae61416468 Merge branch 'main' into feat/i18n-zh 2026-11-01 22:50:55 -03:00
Lucas RayanandClaude Sonnet 5.5 06e8fac0ad fix(header): fit the header on narrow phones after the language selector
CI / Lint e auditorias (push) Successful in 45s
CI / Trivy (dependências e segredos) (push) Successful in 9s
Release / ci (push) Skipped
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m25s
Release / Publica a imagem (linux/arm64) (push) Successful in 20s
Release / Cria a release no Gitea (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:38:30 -03:00
Lucas RayanandClaude Sonnet 5.5 684e0ee6f8 Merge main into feat/i18n-fr-de; changelog 1.5.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:24:34 -03:00
Lucas RayanandClaude Sonnet 5.5 4e99dd3a87 feat(i18n): zh-CN examples log in English, matching the serial-monitor convention
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:11:46 -03:00
Lucas RayanandClaude Sonnet 5.5 2b73b57ee6 feat(i18n): finish zh-CN example comments and align Strapping term with the glossary
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:11:17 -03:00
Lucas RayanandAntigravity 7fce46b9e1 feat(i18n): French and German localization (phase 5)
CI / Lint e auditorias (push) Successful in 49s
CI / Imagem Docker (linux/arm64) (push) Successful in 3m14s
CI / Trivy (dependências e segredos) (push) Successful in 11s
- Add full message catalogs and content for French (fr) and German (de)
- Implement ASCII canonical slugs for French and German routes
- Add language-specific search endpoints (/api/busca/fr, /api/busca/de)
- Configure strict 404 responses for /fr/livro and /de/livro
- Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas
- Add localized code example comments across 14 examples for fr and de
- Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect
- Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 22:06:36 -03:00
Lucas RayanandClaude Sonnet 5.5 1d79051250 feat(i18n): zh-CN content (data, glossary, diagnostics, components, messages, examples)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:06:21 -03:00
Lucas RayanandClaude Sonnet 5.5 ea51aa62b8 docs: changelog 1.4.2
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 17s
Release / Cria a release no Gitea (push) Successful in 6s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:42:00 -03:00
Lucas RayanandClaude Sonnet 5.5 88c6c45267 ci: pass secrets to the reusable CI workflow from the release
CI / Lint e auditorias (push) Successful in 41s
CI / Trivy (dependências e segredos) (push) Successful in 9s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m17s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:38:04 -03:00
Lucas RayanandClaude Sonnet 5.5 fcc3f802aa fix: quadro branco fixo para as fotos das placas oficiais no tema escuro
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
CI / Lint e auditorias (push) Successful in 41s
CI / Trivy (dependências e segredos) (push) Successful in 11s
CI / Imagem Docker (linux/arm64) (push) Failing after 7s
Release / ci (push) Failing after 1m0s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8dT9k6tS5BbPrzYvAv
2026-11-01 21:13:00 -03:00
Lucas RayanandClaude Sonnet 5.5 7b673aeb4b docs: changelog 1.4.0
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 17s
Release / Cria a release no Gitea (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8dT9k6tS5BbPrzYvAv
2026-11-01 20:09:05 -03:00
Lucas RayanandAntigravity 660b28c09d feat(i18n): Spanish localization (phase 4)
CI / Lint e auditorias (push) Successful in 1m31s
CI / Trivy (dependências e segredos) (push) Successful in 10s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m23s
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>
2026-11-01 19:50:20 -03:00
Lucas RayanandClaude Sonnet 5.5 0940814522 docs: changelog 1.3.0
Release / ci (push) Skipped
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Release / Publica a imagem (linux/arm64) (push) Successful in 18s
Release / Cria a release no Gitea (push) Successful in 6s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8dT9k6tS5BbPrzYvAv
2026-11-01 17:45:47 -03:00
Lucas RayanandAntigravity 0d5f8f9c5f fix(i18n): localize json-ld metadata and eliminate breadcrumb leaks
CI / Lint e auditorias (push) Successful in 45s
CI / Trivy (dependências e segredos) (push) Successful in 11s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m23s
- Pass currentLocale to jsonLd.serie and jsonLd.framework to ensure English headline, name, and properties
- Localize JSON-LD @id anchors to #article, #about, #glossary, #organization, and #author for English routes
- Pass isEn prop to PageHero across all internal pages to prevent breadcrumbs from defaulting to Portuguese
- Add scripts/verifica-vazamentos.py to smoke-imagem.sh to permanently test all 36 English URLs (visible text and ld+json)

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 17:42:36 -03:00
Lucas RayanandAntigravity 47c55515bb fix(i18n): eliminate portuguese text leaks across english routes
CI / Lint e auditorias (push) Successful in 50s
CI / Trivy (dependências e segredos) (push) Successful in 10s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m31s
- Localize skip-to-content accessibility link and breadcrumb navigation
- Convert section layouts to dynamic generateMetadata with English titles, descriptions, and structured data
- Eliminate mixed language expressions and translate remaining SoC connection pin warnings and descriptions
- Translate component registry items, categories, tags, and IDF Component Manager guide
- Add strict identical string verification to scripts/check-i18n.mjs with technical allowlist

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 17:17:33 -03:00
Lucas RayanandAntigravity c1bd2c7e11 feat(i18n): English localization (phase 3)
CI / Lint e auditorias (push) Successful in 1m51s
CI / Trivy (dependências e segredos) (push) Successful in 15s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m41s
- Translate content to English across messages/en.json, data/en, lib/data/en, and public/exemplos/en
- Implement localized routing, slugs, and language negotiation with fallback to en
- Build dedicated search index for English with strict book exclusion
- Update components and pages to dynamically render localized strings and datasets
- Verify full structural parity and exact 1:1 match on Portuguese pages via comparator

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 14:17:13 -03:00
Lucas RayanandClaude Sonnet 5.5 22b1f26aed docs: changelog 1.2.0
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 17s
Release / Cria a release no Gitea (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8dT9k6tS5BbPrzYvAv
2026-11-01 12:28:06 -03:00
Lucas RayanandAntigravity d479a8d361 feat(i18n): restrict public routes and metadata to enabled locales
CI / Lint e auditorias (push) Successful in 41s
CI / Trivy (dependências e segredos) (push) Successful in 10s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m5s
- Add ENABLED_LOCALES configuration in i18n/links.js (currently ["pt"])
- Redirect inactive locale prefixes to /pt via 307 in middleware.js
- Restrict root locale negotiation to active locales with fallback to pt
- Hide LanguageSelector when only one locale is enabled
- Generate sitemap, hreflang alternates, and og:locale only for active locales
- Generate static SSG pages only for active locales in build
- Adapt check:i18n and smoke-imagem.sh to validate active vs inactive locales

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 12:10:25 -03:00
Lucas RayanandClaude Sonnet 5.5 3a1a095e97 ci: a real smoke test for the localized routes, and a single redirect from the root
CI / Lint e auditorias (push) Successful in 42s
CI / Trivy (dependências e segredos) (push) Successful in 8s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m11s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:33:40 -03:00
Lucas RayanandClaude Sonnet 5.5 cbf724db2a fix(i18n): keep metadata in the initial <head> for every client
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:30:51 -03:00
Lucas RayanandAntigravity dcd4ef7e1b fix(i18n): extract navigation links module and restore verbatim pt footer
CI / Lint e auditorias (push) Successful in 44s
CI / Trivy (dependências e segredos) (push) Successful in 9s
CI / Imagem Docker (linux/arm64) (push) Successful in 3m56s
- Move getLocalizedHref, LOCALES, and CANONICAL_ROUTES to i18n/links.js to resolve SSR 500 error on home
- Import from @/i18n/links in page.jsx, Header.jsx, Footer.jsx, and LanguageSelector.jsx
- Restore exact production footer texts, author links, and SVG icons in pt
- Verify 100% visible text parity on all pt pages against production with cmp-pt.py

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 10:19:22 -03:00
Lucas RayanandClaude Sonnet 5.5 02dee65b2b fix: regenerate the lockfile with npm 10 so npm ci passes on Node 22
CI / Lint e auditorias (push) Successful in 1m26s
CI / Trivy (dependências e segredos) (push) Successful in 9s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m44s
next-intl pulls @swc/helpers 0.5.23, and the lockfile written by npm 12 (Node 24)
left it out, which npm 10 on the CI and in the Dockerfile rejects.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:03:55 -03:00
Lucas RayanandAntigravity fb59015fca feat(i18n): canonical strings, data extraction and validation (phase 2)
CI / Lint e auditorias (push) Failing after 1m11s
CI / Trivy (dependências e segredos) (push) Successful in 27s
CI / Imagem Docker (linux/arm64) (push) Skipped
Implement Phase 2 of i18n spec:
- Extract UI interface strings to messages/pt.json across 15 namespaces
- Extract canonical data files to data/pt/ (series, frameworks, conexoes)
- Create lib/data/pt/ modules (glossario, diagnostico, componentes, topicos)
- Implement lib/data/index.js async data loaders by locale
- Add automated check:i18n script to validate key parity and enforce no-book rules

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 09:37:44 -03:00
Lucas RayanandAntigravity 83c0ba3e74 feat(i18n): routing and localization infrastructure (phase 1)
Implement Phase 1 of i18n spec:
- Configure next-intl with 6 locales (pt, en, es, fr, de, zh-CN) and pathnames
- Move routes to app/[locale] structure with localized layouts and metadata
- Add middleware for root language negotiation (307), legacy redirects (308), and 404 for non-pt book
- Implement language selector dropdown in header with cookie persistence
- Add system typography rules for zh-CN and word-break/hyphenation for de/fr

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 09:31:22 -03:00
Lucas RayanandClaude Sonnet 5.5 e92aea0c84 release: 1.1.0 changelog
Release / Plano (reaproveitar a imagem?) (push) Successful in 4s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 23s
Release / Cria a release no Gitea (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 08:55:28 -03:00
Lucas RayanandClaude Sonnet 5.5 f6e10a293a ci: keep npm and Next compile caches across image builds
CI / Lint e auditorias (push) Successful in 45s
CI / Trivy (dependências e segredos) (push) Successful in 8s
CI / Imagem Docker (linux/arm64) (push) Successful in 4m11s
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 2m40s
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 08:09:41 -03:00
Lucas RayanandClaude Sonnet 5.5 4ad130a334 ci: build, test and publish the image once, then let the release reuse it
CI / Lint e auditorias (push) Canceled after 46s
CI / Trivy (dependências e segredos) (push) Canceled after 0s
CI / Imagem Docker (linux/arm64) (push) Canceled after 0s
Drop the pull_request trigger (the branch push already validates the commit),
drop the second npm run build from the lint job (the image build compiles it),
and build the image on arm64 after the cheap checks pass. The CI publishes it
as inputs-<hash>, so the merge to main only re-tags it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 08:08:52 -03:00
Lucas RayanandClaude Sonnet 5.5 7d0edf13c4 feat: site search with a dialog in the header and a /api/busca endpoint
CI / Lint, design e build (push) Successful in 1m52s
CI / Trivy (dependências e segredos) (push) Successful in 12s
CI / Imagem Docker (push) Successful in 2m26s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 08:02:57 -03:00
Lucas RayanandClaude Sonnet 5.5 d8323c653b chore: point the repository links to Gitea and swap the GitHub icon
CI / Lint, design e build (push) Canceled after 12s
CI / Trivy (dependências e segredos) (push) Canceled after 0s
CI / Imagem Docker (push) Canceled after 0s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 07:53:39 -03:00
262 changed files with 102943 additions and 5646 deletions

No files matched your search

+52 -26
View File
@@ -3,9 +3,13 @@ name: CI
# Documentação e configuração de ferramenta não mudam nada que a suíte teste.
# Na main não roda por push: o release.yml é quem a chama, e só quando a imagem
# precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit.
# Sem gatilho de pull_request: o push da branch já valida o mesmo commit, e os
# dois juntos rodariam tudo duas vezes (o repositório não recebe PR de fork).
#
# A imagem é construída aqui uma única vez, em arm64 (a arquitetura do servidor),
# testada e publicada como inputs-<hash>. Ao fazer o merge, o release encontra
# essa tag e só aplica os nomes novos, sem rodar nem construir nada de novo.
on:
pull_request:
paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**', '.wolf/**', 'scripts/release-notes.sh']
push:
branches-ignore: [main]
paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**', '.wolf/**', 'scripts/release-notes.sh']
@@ -20,7 +24,7 @@ concurrency:
jobs:
verificar:
name: Lint, design e build
name: Lint e auditorias
runs-on: ubuntu-latest
timeout-minutes: 15
env:
@@ -35,24 +39,11 @@ jobs:
node-version: 22
cache: npm
# Next.js guarda aqui o resultado da compilação anterior; sem isso, cada
# execução recompila todas as páginas do zero.
- name: Cache de build do Next
uses: actions/cache@v4
with:
path: .next/cache
key: next-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}-${{ hashFiles('app/**', 'components/**', 'lib/**') }}
restore-keys: |
next-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}-
next-${{ runner.arch }}-
- run: npm ci
# eslint + auditoria do design system (tokens, contraste AAA) + auditoria de páginas
- run: npm run check
- run: npm run build
# Trivy roda pela imagem oficial: o trivy-action clona o repositório do Trivy
# do mesmo servidor do workflow, que aqui é o Gitea, e não o GitHub.
# O workspace do job é um volume que o daemon não enxerga, então os arquivos
@@ -72,26 +63,61 @@ jobs:
docker rm "$cid" >/dev/null
exit "$status"
# Só começa depois das verificações baratas: um lint quebrado não gasta um
# build de imagem. Roda no runner arm64, o mesmo tipo do servidor, então o
# que é escaneado e testado é a imagem que vai ao ar.
imagem:
name: Imagem Docker
runs-on: ubuntu-latest
name: Imagem Docker (linux/arm64)
needs: [verificar, seguranca]
runs-on: ubuntu-24.04-arm
env:
REGISTRY: git.lucasrguerra.dev.br
steps:
- uses: actions/checkout@v4
# `docker build` simples: o cache de camadas fica no volume persistente do
# daemon do runner, e o buildx criaria um BuildKit novo a cada job.
# Conteúdo já publicado (re-push, tag num commit já validado): nada a fazer.
- id: plano
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
- if: ${{ steps.plano.outputs.reuse != 'true' }}
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
# `docker build` simples, no daemon persistente do runner: as camadas e os
# cache mounts do Dockerfile (npm e compilação do Next) sobrevivem entre
# execuções. Um buildx criaria um BuildKit novo, e vazio, a cada job.
- name: Build
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: docker build -t espdocs:ci .
- name: Trivy na imagem
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
image --severity HIGH,CRITICAL --exit-code 1 espdocs:ci
# Rotas por idioma, redirects e regras do livro (scripts/smoke-imagem.sh).
# Um curl só na raiz não basta: ela redireciona, e uma página interna
# quebrada ainda passaria.
- name: A imagem sobe e responde
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
docker run -d --name espdocs-ci --network host -e PORT=3999 espdocs:ci
for i in $(seq 1 30); do
curl -fsS http://127.0.0.1:3999/ >/dev/null && ok=1 && break
sleep 2
done
docker logs espdocs-ci | tail -5
status=0
scripts/smoke-imagem.sh http://127.0.0.1:3999 || status=1
docker logs espdocs-ci | tail -15
# O Next registra falhas de render no log mesmo quando responde.
if docker logs espdocs-ci 2>&1 | grep -q '⨯'; then echo "O servidor registrou erro de render"; status=1; fi
docker rm -f espdocs-ci >/dev/null
test "${ok:-0}" = 1
exit "$status"
# Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir.
- name: Publica inputs-<hash>
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
tag="${{ steps.plano.outputs.image }}:inputs-${{ steps.plano.outputs.inputs }}"
docker tag espdocs:ci "$tag"
docker push "$tag"
+15 -23
View File
@@ -18,10 +18,10 @@ env:
jobs:
# A imagem só depende dos arquivos que entram no build, não da documentação nem
# da configuração de ferramentas. Quando já existe no registro uma imagem para
# o mesmo conteúdo (um merge só de docs, uma mudança de workflow, uma tag num
# commit que acabou de ser publicado), não há o que construir: as tags novas
# apontam para o manifesto existente.
# da configuração de ferramentas. O push da branch já a construiu, testou e
# publicou como inputs-<hash>; quando essa tag existe (o caso normal de um
# merge, uma tag num commit validado, um merge só de docs), não há o que
# construir: as tags novas apontam para o manifesto existente.
plano:
name: Plano (reaproveitar a imagem?)
runs-on: ubuntu-latest
@@ -32,23 +32,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- id: plano
env:
REPO: ${{ gitea.repository }}
run: |
inputs=$(git ls-tree -r HEAD \
| awk -F'\t' '$2 !~ /^(\.gitea|\.github|\.claude|\.superset|docs)\// && $2 !~ /^(README.*|CLAUDE\.md|DESIGN\.md|LICENSE|\.gitignore|CHANGELOG\.md|scripts\/release-notes\.sh)$/' \
| sha256sum | cut -c1-16)
ns="${REPO,,}"
token=$(curl -fsS "https://$REGISTRY/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
-H "Authorization: Bearer $token" \
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.manifest.v1+json' \
"https://$REGISTRY/v2/$ns/manifests/inputs-$inputs")
echo "inputs-$inputs -> HTTP $code"
reuse=false; [ "$code" = 200 ] && reuse=true
echo "inputs=$inputs" >> "$GITHUB_OUTPUT"
echo "reuse=$reuse" >> "$GITHUB_OUTPUT"
echo "image=$REGISTRY/$ns" >> "$GITHUB_OUTPUT"
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
# Nada é publicado sem a suíte completa passar antes. Pulada quando a imagem é
# reaproveitada: o mesmo conteúdo já passou por ela.
@@ -56,6 +40,9 @@ jobs:
needs: plano
if: ${{ needs.plano.outputs.reuse != 'true' }}
uses: ./.gitea/workflows/ci.yml
# Um workflow reutilizável não herda os secrets sozinho: sem isto o login no
# registro recebe senha vazia ("Password required").
secrets: inherit
publicar:
name: Publica a imagem (linux/arm64)
@@ -68,6 +55,11 @@ jobs:
steps:
- uses: actions/checkout@v4
# Se o ci chamado acima acabou de publicar a imagem (push direto na main),
# o plano lá de cima está desatualizado: confere de novo antes de construir.
- id: replano
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@v4
- name: Autentica no registro
@@ -89,7 +81,7 @@ jobs:
type=sha,format=long
- name: Build e push
if: ${{ needs.plano.outputs.reuse != 'true' }}
if: ${{ steps.replano.outputs.reuse != 'true' }}
uses: docker/build-push-action@v7
with:
context: .
@@ -104,7 +96,7 @@ jobs:
# Mesmo manifesto, nomes novos: nenhuma camada é lida nem escrita.
- name: Aplica as tags à imagem existente
if: ${{ needs.plano.outputs.reuse == 'true' }}
if: ${{ steps.replano.outputs.reuse == 'true' }}
run: |
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
docker buildx imagetools create $tags "${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}"
+175 -1
View File
@@ -6,6 +6,172 @@ Tudo o que muda de relevante no ESPDocs está aqui. O formato segue o
## [Não lançado]
## [1.6.0] - 2026-11-02
### Adicionado
- Chinês simplificado (`/zh-CN`), o sexto idioma do site, com o mesmo conteúdo dos
demais, menos o livro (`/zh-CN/livro` responde 404):
- Interface, séries, frameworks, diagramas de pinos, glossário, diagnóstico,
componentes e exemplos de código com comentários em chinês (mensagens de log
dos exemplos ficam em inglês, para não aparecerem quebradas no monitor serial).
- Busca em chinês: o motor entende consultas como `s3 闪存`, `c6 usb 引脚` ou
`哪款 esp32 有 psram`, segmentando o texto com `Intl.Segmenter`.
- SEO próprio (`hreflang`, sitemap, JSON-LD em `zh-CN`) e negociação da raiz:
`Accept-Language` com `zh`, `zh-Hans` ou `zh-TW` leva a `/zh-CN`.
- O filtro alfabético A–Z do glossário não aparece em chinês.
- `scripts/verifica-busca.mjs`, chamado pelo teste de fumaça: roda o motor de busca
sobre o índice de cada idioma e confere que as respostas e os links estão no
idioma da página.
- `check-i18n` passa a procurar português dentro dos dados dos outros idiomas.
### Corrigido
- Na busca, as respostas diretas (por exemplo "Flash no ESP32-S3", "Dados da série",
"Pinos do ESP32-S3 ligados à memória flash") saíam em português em inglês, espanhol,
francês e alemão, e levavam a `/series/...` em vez do idioma da página. Agora
textos e links seguem o idioma.
- Em francês e alemão, valores de ADC, SPI, toque capacitivo, consumo e outros ainda
estavam em português (por exemplo "até 18 canais", "conforme a carga"); em espanhol,
dois valores de consumo. Todos traduzidos.
- O seletor de chip reconhecia "Sim"/"Yes" para Matter, Arduino e segurança, mas não
"Sí", "Oui" nem "Ja"; agora reconhece os seis idiomas.
- A home em alemão mostrava "14 frameworks" em minúscula.
## [1.5.0] - 2026-11-02
### Adicionado
- Internacionalização completa para os idiomas Francês (`fr`) e Alemão (`de`) (Fase 5):
- Ativação do francês e do alemão em `ENABLED_LOCALES = ["pt", "en", "es", "fr", "de"]` e no seletor de idiomas do cabeçalho.
- Tradução técnica integral e paridade estrutural em `messages/fr.json` e `messages/de.json` (15 namespaces), nos arquivos de dados em `data/{fr,de}/` (`series.json`, `frameworks.json`, `conexoes/*.json`) e `lib/data/{fr,de}/` (`glossario.js`, `diagnostico.js`, `componentes.js`, `topicos.js`).
- Tradução técnica natural com tratamento formal respeitado: "vous" em francês e "Sie" em alemão.
- 14 exemplos práticos de código com comentários em francês e 14 em alemão em `public/exemplos/{fr,de}/`.
- Slugs canônicos ASCII por idioma:
- Francês: `/fr/series`, `/fr/catalogue`, `/fr/comparaison`, `/fr/composants`, `/fr/diagnostic`, `/fr/frameworks`, `/fr/glossaire`, `/fr/selecteur`, `/fr/a-propos`.
- Alemão: `/de/serien`, `/de/katalog`, `/de/vergleich`, `/de/komponenten`, `/de/diagnose`, `/de/frameworks`, `/de/glossar`, `/de/auswahl`, `/de/ueber-uns`.
- Busca dedicada por idioma em `/api/busca/fr` e `/api/busca/de` com normalização de acentos, caracteres alemães (ä, ö, ü, ß) e ligaduras francesas (œ, æ), sem menção ao livro e com links diretos aos slugs canônicos.
- Exclusão total e estrita de referências ao livro fora do português, com `/fr/livro` e `/de/livro` respondendo HTTP 404 estrito.
- Tabela do catálogo de placas com colunas traduzidas e mapeamento de valores técnicos nos idiomas francês e alemão.
- Negociação de idioma na raiz com roteamento para `fr` ou `de` com base nos cabeçalhos Accept-Language ou cookies `NEXT_LOCALE=fr` / `NEXT_LOCALE=de`, e fallback padrão para `en` para navegadores com o idioma inativo restante (`zh-CN`).
- Metadados de SEO, Open Graph e Twitter Cards localizados com `og:locale` (`fr_FR`, `de_DE`), `inLanguage` (`fr`, `de`) e `hreflang` cruzado entre `pt-BR`, `en`, `es-419`, `fr-FR`, `de-DE` e `x-default`.
- Suporte CSS com hifenação automática (`hyphens: auto`) para alemão e francês via atributo `lang` dinâmico no layout raiz.
- Extensão da suíte de verificação: `scripts/check-i18n.mjs` valida `fr` e `de`, `scripts/smoke-imagem.sh` testa as rotas francesas e alemãs e `scripts/verifica-vazamentos.py` varre todas as 36 rotas em francês e 36 em alemão (texto visível e blocos JSON-LD).
### Corrigido
- O cabeçalho passou a caber em telas estreitas. Desde o seletor de idioma, a faixa de
ícones ficava com ~410 px de largura mínima e o botão do menu era cortado em
celulares (390 e 360 px). Agora o seletor fica compacto no celular e o logo mostra
só o ícone abaixo de 360 px; sem rolagem horizontal de 320 px para cima.
## [1.4.2] - 2026-11-02
### Corrigido
- A release passa os segredos ao workflow de CI que chama (`secrets: inherit`). Sem isso,
uma release que precisava construir a imagem falhava no login do registro.
- Inclui a correção da 1.4.1: a tag `v1.4.1` não chegou a ter release, porque a CI
dela falhou pelo problema acima.
## [1.4.1] - 2026-11-01
### Corrigido
- As fotos das placas de desenvolvimento oficiais na página de cada série foram feitas
para fundo claro e ficavam ruins no tema escuro. O quadro delas agora é sempre
branco, nos dois temas; o resto do site continua seguindo o tema.
## [1.4.0] - 2026-11-01
### Adicionado
- Internacionalização completa para o idioma espanhol neutro latino-americano (`es`) (Fase 4):
- Ativação do espanhol em `ENABLED_LOCALES = ["pt", "en", "es"]` e no seletor de idiomas do cabeçalho.
- Tradução técnica integral e paridade estrutural em `messages/es.json` (15 namespaces) e arquivos de dados em `data/es/` (`series.json`, `frameworks.json`, `conexoes/*.json`) e `lib/data/es/` (`glossario.js`, `diagnostico.js`, `componentes.js`, `topicos.js`).
- 14 exemplos práticos de código com comentários em espanhol em `public/exemplos/es/`.
- Roteamento com slugs canônicos em espanhol (`/es/catalogo`, `/es/comparacion`, `/es/componentes`, `/es/diagnostico`, `/es/frameworks`, `/es/glosario`, `/es/selector`, `/es/acerca`).
- Busca por idioma em `/api/busca/es` com normalização de acentos e 'ñ', sem menção ao livro e com links para os slugs canônicos em espanhol.
- Exclusão total e estrita de referências ao livro no idioma espanhol (menu, rodapé, busca, sitemap e metadados), mantendo `/es/livro` respondendo HTTP 404.
- Tabela de catálogo com cabeçalhos traduzidos e mapeamento de valores na interface em espanhol.
- Negociação de idioma na raiz com roteamento para `es` para cabeçalhos Accept-Language `es-*` ou cookie `NEXT_LOCALE=es`, e fallback padrão para `en` para navegadores com idiomas inativos (`fr`, `de`, `zh-CN`).
- Metadados de SEO, Open Graph e Twitter Cards localizados com `og:locale` (`es_419`), `inLanguage` (`es-419`) e `hreflang` cruzado entre `pt-BR`, `en`, `es-419` e `x-default`.
- Extensão dos scripts de verificação: `scripts/check-i18n.mjs` valida `es`, `scripts/smoke-imagem.sh` testa as rotas espanholas e `scripts/verifica-vazamentos.py` varre as 36 rotas em espanhol (texto visível e JSON-LD).
## [1.3.0] - 2026-11-01
### Adicionado
- Internacionalização completa para o idioma inglês (`en`) (Fase 3):
- Ativação do inglês em `ENABLED_LOCALES = ["pt", "en"]` com reexibição do seletor de idiomas no cabeçalho.
- Tradução técnica integral e paridade estrutural em `messages/en.json` (15 namespaces) e arquivos de dados em `data/en/` (`series.json`, `frameworks.json`, `conexoes/*.json`) e `lib/data/en/` (`glossario.js`, `diagnostico.js`, `componentes.js`, `topicos.js`).
- 14 exemplos práticos de código com comentários em inglês em `public/exemplos/en/`.
- Roteamento com slugs canônicos em inglês (`/en/catalog`, `/en/compare`, `/en/components`, `/en/diagnostics`, `/en/frameworks`, `/en/glossary`, `/en/selector`, `/en/about`).
- Índice de busca dedicado por idioma em `/api/busca/[locale]`, com links direcionando aos slugs do idioma correspondente e caixa de busca localizada.
- Exclusão total e estrita de referências ao livro no idioma inglês (menu, rodapé, busca, sitemap e metadados), mantendo `/en/livro` respondendo HTTP 404.
- Tabela de catálogo com cabeçalhos traduzidos e mapeamento de valores na interface inglesa.
- Negociação de idioma na raiz com fallback padrão para `en` para navegadores com idiomas inativos ou genéricos, e redirecionamento 307 de prefixos inativos (`es`, `fr`, `de`, `zh-CN`) para `/en` preservando o mapeamento de slugs.
- Metadados de SEO, Open Graph e Twitter Cards localizados, com `hreflang` cruzado entre `pt-BR`, `en` e `x-default`.
- Verificações permanentes contra vazamento de português no inglês: `scripts/check-i18n.mjs` falha em textos idênticos entre `pt` e `en` (fora de uma lista de termos técnicos), e `scripts/verifica-vazamentos.py`, chamado pelo teste de fumaça da CI, varre as 36 rotas em inglês, texto visível e JSON-LD.
### Alterado
- A raiz `/` passa a levar quem não fala português ao inglês (`/en`); o português continua em `/pt`. Idiomas ainda sem tradução (`es`, `fr`, `de`, `zh-CN`) redirecionam para `/en`.
## [1.2.0] - 2026-11-01
### Adicionado
- Infraestrutura de internacionalização com `next-intl` (Fase 1):
- Roteamento com prefixo de idioma sob `app/[locale]/`, com 6 locales declarados (`pt`, `en`, `es`, `fr`, `de`, `zh-CN`).
- `middleware.js` com negociação de idioma na raiz por cookie `NEXT_LOCALE` e cabeçalho `Accept-Language` (com pesos `q`), redirecionamento 308 de URLs antigas sem prefixo para `/pt/`, e retorno 404 para `/livro` fora do português.
- Seletor de idiomas acessível no cabeçalho com atalho para os 6 idiomas, persistência via cookie `NEXT_LOCALE` e mapeamento de rota correspondente.
- Regras de tipografia de sistema CJK para `zh-CN` e hifenização/quebra de palavras para `de` e `fr`.
- Extração de strings e dados canônicos (Fase 2):
- Catálogo de mensagens canônico `messages/pt.json` cobrindo 15 namespaces de páginas e componentes sem alteração de conteúdo.
- Conjunto de dados canônicos em `data/pt/` (`series.json`, `frameworks.json`, `conexoes/*.json`) e módulos em `lib/data/pt/` (`glossario.js`, `diagnostico.js`, `componentes.js`, `topicos.js`) com carregadores por locale em `lib/data/index.js`.
- Script automatizado de validação `check:i18n` integrado ao `npm run check`, verificando paridade de chaves, ausência de valores vazios e garantia estrita de ausência de referências ao livro fora do português.
- Controle de idiomas ativos e proteção contra conteúdo não traduzido:
- Configuração centralizada em `i18n/links.js` (`ENABLED_LOCALES`), atualmente restrita a `["pt"]`.
- Redirecionamento 307 de qualquer prefixo de idioma inativo para `/pt` preservando o caminho ou mapeamento equivalente.
- Negociação de idioma na raiz selecionando unicamente entre os idiomas ativos (com fallback em `pt`).
- Seletor de idiomas no cabeçalho oculto enquanto apenas um idioma estiver ativo.
- Sitemap, hreflang/alternates e build SSG restritos aos idiomas ativos.
### Alterado
- Todas as páginas passam a viver sob `/pt/` (por exemplo `/pt/series`). As URLs
antigas, sem prefixo, redirecionam com 308 para o endereço novo, e a raiz `/`
redireciona para o idioma negociado. O conteúdo do site em português não mudou.
- O teste de subida da imagem na CI virou `scripts/smoke-imagem.sh`: confere as
rotas de cada idioma, a negociação de `Accept-Language`, os redirects 308 das
URLs antigas, o 404 do livro fora do português e a metadata no `<head>`, e
falha se o servidor registrar erro de render. O `curl` só na raiz deixou passar
uma home quebrada.
- A metadata (título, `canonical`, Open Graph) sempre sai no `<head>` do HTML
inicial, para qualquer cliente, como já era antes do i18n.
- A raiz `/` redireciona direto para `/<idioma>`, em um salto só.
## [1.1.0] - 2026-11-01
### Adicionado
- Busca no site, aberta pelo botão do cabeçalho ou por Ctrl/⌘+K. O índice
(séries, frameworks, glossário, erros de diagnóstico, componentes e conexões)
é gerado no build, em `/api/busca`.
### Alterado
- Os links do repositório do projeto (rodapé, "Sobre", dados estruturados)
apontam para o Gitea, e o ícone do GitHub virou o do Gitea. Os links dos
frameworks da Espressif continuam no GitHub, porque os repositórios são deles.
- O site passou a rodar na Oracle, a partir da imagem Docker do registro do
Gitea, em `espdocs.cienciaembarcada.com.br` e `espdocs.lucasrguerra.dev.br`.
- CI: a imagem é construída, escaneada e testada uma vez, em arm64, no push da
branch, e o release só aplica as tags; o gatilho `pull_request` (que repetia o
push) e o segundo `next build` do job de lint saíram, e os caches do npm e da
compilação do Next ficam entre as execuções.
## [1.0.0] - 2026-10-30
A primeira versão com tag. O trabalho anterior nunca foi tagueado, então esta
@@ -60,5 +226,13 @@ entrada resume tudo desde o primeiro commit, em 2025-10-21, até a imagem Docker
otimização de imagens (GHSA-2464-fhr4-w9xw), e `postcss` fixado acima da cópia
embutida no `next`.
[Não lançado]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.0.0...HEAD
[Não lançado]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.6.0...HEAD
[1.6.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.5.0...v1.6.0
[1.5.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.4.2...v1.5.0
[1.4.2]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.4.1...v1.4.2
[1.4.1]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.4.0...v1.4.1
[1.4.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.3.0...v1.4.0
[1.3.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.2.0...v1.3.0
[1.2.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.1.0...v1.2.0
[1.1.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/compare/v1.0.0...v1.1.0
[1.0.0]: https://git.lucasrguerra.dev.br/lucasrguerra/ESPDocs/releases/tag/v1.0.0
+4 -2
View File
@@ -6,14 +6,16 @@ WORKDIR /app
# O Puppeteer só é usado em scripts locais (slides, capturas): não baixa o Chrome.
ENV PUPPETEER_SKIP_DOWNLOAD=true
COPY package.json package-lock.json ./
RUN npm ci
# Cache do npm no daemon: dependências já baixadas não vão à rede de novo.
RUN --mount=type=cache,target=/root/.npm npm ci
FROM node:22-alpine AS build
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1 NEXT_OUTPUT=standalone
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Cache de compilação do Next: só as páginas que mudaram são recompiladas.
RUN --mount=type=cache,target=/app/.next/cache npm run build
FROM node:22-alpine
WORKDIR /app
+81
View File
@@ -0,0 +1,81 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isEn ? "ESP32 Board Catalog" : isEs ? "Catálogo de placas ESP32" : isFr ? "Catalogue de cartes ESP32" : isZh ? "ESP32 开发板目录" : isDe ? "ESP32-Board-Katalog" : "Catálogo de placas ESP32",
descricao: isEn
? "ESP32 development boards and DevKits available in Brazil, with filters by series, connector, and USB-serial converter."
: isEs
? "Placas de desarrollo y DevKits con ESP32, con filtros por serie, conector y conversor USB-serial."
: isFr
? "Cartes de développement et DevKits ESP32, avec filtres par série, connecteur et convertisseur USB-série."
: isZh ? "带有 ESP32 的开发板,可按系列、接口和 USB 转串口芯片筛选。" : isDe
? "ESP32-Entwicklungsboards und DevKits, mit Filtern nach Serie, Anschluss und USB-Seriell-Wandler."
: "Placas de desenvolvimento com ESP32 disponíveis no Brasil, com filtro por série, conector e conversor USB-serial.",
caminho: "/catalogo",
locale,
keywords: isEn
? ["ESP32 boards", "ESP32 DevKit", "buy ESP32", "ESP32 DevKitC"]
: isEs
? ["placas ESP32", "DevKit ESP32", "comprar ESP32", "ESP32 DevKitC"]
: isFr
? ["cartes ESP32", "DevKit ESP32", "acheter ESP32", "ESP32 DevKitC"]
: isZh ? ["ESP32 开发板", "ESP32 DevKit", "购买 ESP32", "ESP32 DevKitC"] : isDe
? ["ESP32 Boards", "ESP32 DevKit", "ESP32 kaufen", "ESP32 DevKitC"]
: ["placas ESP32", "DevKit ESP32", "comprar ESP32", "ESP32 DevKitC"],
});
}
export default async function Layout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const canonPath = isEn ? "/en/catalog" : isEs ? "/es/catalogo" : isFr ? "/fr/catalogue" : isZh ? "/zh-CN/catalog" : isDe ? "/de/katalog" : "/catalogo";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isEn ? "ESP32 Development Board Catalog" : isEs ? "Catálogo de placas de desarrollo ESP32" : isFr ? "Catalogue de cartes de développement ESP32" : isZh ? "ESP32 开发板目录" : isDe ? "Katalog für ESP32-Entwicklungsboards" : "Catálogo de Placas ESP32",
descricao: isEn
? "Interactive guide and catalog of development boards and DevKits featuring ESP32 microcontrollers."
: isEs
? "Guía y catálogo interactivo de placas de desarrollo y DevKits con microcontroladores ESP32."
: isFr
? "Guide interactif et catalogue de cartes de développement et DevKits avec microcontrôleurs ESP32."
: isZh ? "带有 ESP32 微控制器的开发板与 DevKit 的交互式指南与目录。" : isDe
? "Interaktiver Leitfaden und Katalog für Entwicklungsboards und DevKits mit ESP32-Mikrocontrollern."
: "Guia e catálogo interativo de placas de desenvolvimento e DevKits com microcontroladores ESP32.",
caminho: canonPath,
locale,
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEn ? "Home" : isEs ? "Inicio" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEn ? "/en" : isEs ? "/es" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: isEn ? "Board Catalog" : isEs ? "Catálogo de placas" : isFr ? "Catalogue de cartes" : isZh ? "开发板目录" : isDe ? "Board-Katalog" : "Catálogo de Placas", caminho: canonPath },
])
),
}}
/>
{children}
</>
);
}
+505
View File
@@ -0,0 +1,505 @@
"use client";
import { useState, useEffect } from "react";
import { usePathname } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import BoardCard from "@/components/BoardCard";
import { AlertTriangle, RefreshCw, Search, ShoppingCart, SlidersHorizontal } from "lucide-react";
const HEADER_MAP_EN = {
"Nome": "Name",
"Descrição": "Description",
"Série": "Series",
"Loja Oficial": "Official Store",
"Fabricante": "Manufacturer",
"Processador": "Processor",
"Memória Flash": "Flash Memory",
"PSRAM": "PSRAM",
"Conector USB": "USB Connector",
"Interface USB": "USB Interface",
"Antena": "Antenna",
"Bateria": "Battery",
"Display": "Display",
"Sensores": "Sensors",
"Botões": "Buttons",
"LEDs": "LEDs",
};
const VALUE_MAP_EN = {
"Sim": "Yes",
"Não": "No",
"Opcional": "Optional",
};
const HEADER_MAP_ES = {
"Nome": "Nombre",
"Descrição": "Descripción",
"Série": "Serie",
"Loja Oficial": "Tienda oficial",
"Fabricante": "Fabricante",
"Processador": "Procesador",
"Memória Flash": "Memoria flash",
"PSRAM": "PSRAM",
"Conector USB": "Conector USB",
"Interface USB": "Interfaz USB",
"Antena": "Antena",
"Bateria": "Batería",
"Display": "Pantalla",
"Sensores": "Sensores",
"Botões": "Botones",
"LEDs": "LEDs",
};
const VALUE_MAP_ES = {
"Sim": "Sí",
"Não": "No",
"Opcional": "Opcional",
};
const HEADER_MAP_FR = {
"Nome": "Nom",
"Descrição": "Description",
"Série": "Série",
"Loja Oficial": "Boutique officielle",
"Fabricante": "Fabricant",
"Processador": "Processeur",
"Memória Flash": "Mémoire Flash",
"PSRAM": "PSRAM",
"Conector USB": "Connecteur USB",
"Interface USB": "Interface USB",
"Antena": "Antenne",
"Bateria": "Batterie",
"Display": "Écran",
"Sensores": "Capteurs",
"Botões": "Boutons",
"LEDs": "LEDs",
};
const VALUE_MAP_FR = {
"Sim": "Oui",
"Não": "Non",
"Opcional": "Optionnel",
};
const HEADER_MAP_DE = {
"Nome": "Name",
"Descrição": "Beschreibung",
"Série": "Serie",
"Loja Oficial": "Offizieller Store",
"Fabricante": "Hersteller",
"Processador": "Prozessor",
"Memória Flash": "Flash-Speicher",
"PSRAM": "PSRAM",
"Conector USB": "USB-Anschluss",
"Interface USB": "USB-Schnittstelle",
"Antena": "Antenne",
"Bateria": "Batterie",
"Display": "Display",
"Sensores": "Sensoren",
"Botões": "Tasten",
"LEDs": "LEDs",
};
const HEADER_MAP_ZH = {
"Nome": "名称",
"Descrição": "描述",
"Série": "系列",
"Loja Oficial": "官方商店",
"Fabricante": "制造商",
"Processador": "处理器",
"Memória Flash": "闪存",
"PSRAM": "PSRAM",
"Conector USB": "USB 接口",
"Interface USB": "USB 接口类型",
"Antena": "天线",
"Bateria": "电池",
"Display": "显示屏",
"Sensores": "传感器",
"Botões": "按键",
"LEDs": "LEDs",
};
const VALUE_MAP_DE = {
"Sim": "Ja",
"Não": "Nein",
"Opcional": "Optional",
};
const VALUE_MAP_ZH = {
"Sim": "是",
"Não": "否",
"Opcional": "可选",
};
export default function PlacasPage() {
const pathname = usePathname() || "";
const isEn = pathname === "/en" || pathname.startsWith("/en/");
const isEs = pathname === "/es" || pathname.startsWith("/es/");
const isFr = pathname === "/fr" || pathname.startsWith("/fr/");
const isDe = pathname === "/de" || pathname.startsWith("/de/");
const isZh = pathname === "/zh-CN" || pathname.startsWith("/zh-CN/");
const [boards, setBoards] = useState([]);
const [filteredBoards, setFilteredBoards] = useState([]);
const [headers, setHeaders] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [searchTerm, setSearchTerm] = useState("");
const [activeFilters, setActiveFilters] = useState({});
const [filterOptions, setFilterOptions] = useState({});
const [filtrosAbertos, setFiltrosAbertos] = useState(false);
const excludedColumns = ["Nome", "Descrição", "Link", "Imagem", "Loja Oficial"];
useEffect(() => {
fetchBoards();
setFiltrosAbertos(window.matchMedia("(min-width: 1024px)").matches);
}, []);
useEffect(() => {
applyFilters();
}, [boards, searchTerm, activeFilters]);
const fetchBoards = async () => {
try {
setLoading(true);
const response = await fetch("/api/placas");
if (!response.ok) {
throw new Error(isEn ? "Failed to load board data" : isEs ? "Error al cargar los datos de las placas" : isFr ? "Erreur lors du chargement des données des cartes" : isZh ? "加载开发板数据出错" : isDe ? "Fehler beim Laden der Board-Daten" : "Erro ao carregar dados das placas");
}
const result = await response.json();
setBoards(result.data);
setHeaders(result.headers);
setFilteredBoards(result.data);
generateFilterOptions(result.data, result.headers);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const generateFilterOptions = (data, headers) => {
const options = {};
const filterableColumns = headers.filter((h) => !excludedColumns.includes(h));
filterableColumns.forEach((column) => {
const uniqueValues = new Set();
data.forEach((item) => {
const value = item[column];
if (value && value.toString().trim()) {
uniqueValues.add(value.toString().trim());
}
});
const values = Array.from(uniqueValues).sort();
const binaryValues = ["Sim", "Não", "Opcional"];
const isBinaryFilter = values.every((v) => binaryValues.includes(v));
options[column] = {
values: values,
isBinary: isBinaryFilter,
};
});
setFilterOptions(options);
};
const applyFilters = () => {
let filtered = [...boards];
if (searchTerm) {
filtered = filtered.filter((board) => {
const searchLower = searchTerm.toLowerCase();
return (
board.Nome?.toLowerCase().includes(searchLower) ||
board.Descrição?.toLowerCase().includes(searchLower)
);
});
}
Object.keys(activeFilters).forEach((column) => {
if (activeFilters[column] && activeFilters[column].length > 0) {
filtered = filtered.filter((board) => {
const boardValue = board[column]?.toString().trim();
if (activeFilters[column].includes("binary-enabled")) {
return boardValue === "Sim" || boardValue === "Opcional";
}
return activeFilters[column].includes(boardValue);
});
}
});
setFilteredBoards(filtered);
};
const handleFilterToggle = (column, value) => {
setActiveFilters((prev) => {
const newFilters = { ...prev };
if (!newFilters[column]) {
newFilters[column] = [value];
} else {
const index = newFilters[column].indexOf(value);
if (index > -1) {
newFilters[column] = newFilters[column].filter((v) => v !== value);
if (newFilters[column].length === 0) {
delete newFilters[column];
}
} else {
newFilters[column] = [...newFilters[column], value];
}
}
return newFilters;
});
};
const clearFilters = () => {
setActiveFilters({});
setSearchTerm("");
};
const activeFilterCount = Object.keys(activeFilters).length + (searchTerm ? 1 : 0);
const filterableColumns = headers.filter((h) => !excludedColumns.includes(h));
const hero = (
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEn ? "Board Catalog" : isEs ? "Catálogo de placas" : isFr ? "Catalogue de cartes" : isZh ? "开发板目录" : isDe ? "Board-Katalog" : "Catálogo de placas" }]}
icon={ShoppingCart}
label={isEn ? "Real DevKits and modules" : isEs ? "DevKits y módulos reales" : isFr ? "DevKits et modules réels" : isZh ? "真实的 DevKit 与模组" : isDe ? "Echte DevKits und Module" : "DevKits e módulos reais"}
title={isEn ? "ESP32 Board Catalog" : isEs ? "Catálogo de placas ESP32" : isFr ? "Catalogue de cartes ESP32" : isZh ? "ESP32 开发板目录" : isDe ? "ESP32-Board-Katalog" : "Catálogo de placas ESP32"}
lede={
isEn
? "Compare official and third-party boards for your project: USB interface, on-board sensors and direct store links."
: isEs
? "Compare placas oficiales y alternativas para su proyecto: interfaz USB, sensores integrados y enlace directo a la tienda."
: isFr
? "Comparez les cartes officielles et alternatives pour votre projet : interface USB, capteurs intégrés et lien direct vers la boutique."
: isZh ? "对比官方与替代开发板,为你的项目选型:USB 接口、板载传感器,以及直达商店的链接。" : isDe
? "Vergleichen Sie offizielle und Drittanbieter-Boards für Ihr Projekt: USB-Schnittstelle, integrierte Sensoren und direkter Store-Link."
: "Compare placas oficiais e alternativas para o seu projeto: interface USB, sensores integrados e link direto para a loja."
}
/>
);
if (loading) {
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10" aria-busy="true" aria-label={isEn ? "Loading boards" : isEs ? "Cargando placas" : isFr ? "Chargement des cartes" : isZh ? "正在加载开发板" : isDe ? "Boards werden geladen" : "Carregando placas"}>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="card h-72 animate-pulse bg-surface-2" />
))}
</div>
<p role="status" className="mt-6 text-center text-sm text-muted">
{isEn ? "Querying boards database…" : isEs ? "Consultando la base de datos de placas…" : isFr ? "Consultation de la base de cartes…" : isZh ? "正在查询开发板数据库…" : isDe ? "Board-Datenbank wird abgefragt…" : "Consultando o banco de placas…"}
</p>
</section>
</main>
<Footer />
</div>
);
}
if (error) {
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10">
<div role="alert" className="callout callout-danger flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-danger" aria-hidden="true" />
<div>
<p className="font-semibold text-ink">
{isEn ? "Could not load boards" : isEs ? "No se pudieron cargar las placas" : isFr ? "Impossible de charger les cartes" : isZh ? "无法加载开发板" : isDe ? "Boards konnten nicht geladen werden" : "Não foi possível carregar as placas"}
</p>
<p className="mt-1">
{error}. {isEn ? "Check your connection and try again." : isEs ? "Compruebe la conexión y vuelva a intentarlo." : isFr ? "Vérifiez votre connexion et réessayez." : isZh ? "请检查网络连接后重试。" : isDe ? "Prüfen Sie Ihre Verbindung und versuchen Sie es erneut." : "Verifique a conexão e tente de novo."}
</p>
<button type="button" onClick={fetchBoards} className="btn btn-primary btn-sm mt-4">
<RefreshCw className="h-4 w-4" aria-hidden="true" />
{isEn ? "Try again" : isEs ? "Reintentar" : isFr ? "Réessayer" : isZh ? "重试" : isDe ? "Erneut versuchen" : "Tentar novamente"}
</button>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
const filtros = (
<div className="space-y-6">
<div>
<label htmlFor="busca-placa" className="text-sm font-semibold text-ink">
{isEn ? "Search board" : isEs ? "Buscar placa" : isFr ? "Rechercher une carte" : isZh ? "搜索开发板" : isDe ? "Board suchen" : "Buscar placa"}
</label>
<div className="relative mt-2">
<Search className="pointer-events-none absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-placa"
type="search"
placeholder={isEn ? "Name or description" : isEs ? "Nombre o descripción" : isFr ? "Nom ou description" : isZh ? "名称或描述" : isDe ? "Name oder Beschreibung" : "Nome ou descrição"}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="field pl-10 text-sm"
/>
</div>
</div>
{filterableColumns.map((column) => {
const filterData = filterOptions[column];
if (!filterData) return null;
const colLabel = isEn ? (HEADER_MAP_EN[column] || column) : isEs ? (HEADER_MAP_ES[column] || column) : isFr ? (HEADER_MAP_FR[column] || column) : isZh ? (HEADER_MAP_ZH[column] || column) : isDe ? (HEADER_MAP_DE[column] || column) : column;
if (filterData.isBinary) {
return (
<label key={column} className="flex min-h-11 cursor-pointer items-center justify-between gap-3 border-t border-line pt-4 text-sm font-medium text-ink-soft">
{colLabel}
<input
type="checkbox"
checked={activeFilters[column]?.includes("binary-enabled") || false}
onChange={() => handleFilterToggle(column, "binary-enabled")}
className="h-5 w-5 shrink-0 cursor-pointer accent-[var(--accent)]"
/>
</label>
);
}
return (
<fieldset key={column} className="border-t border-line pt-4">
<legend className="flex items-center gap-2 pr-2 text-sm font-semibold text-ink">
{colLabel}
{activeFilters[column]?.length > 0 && <span className="chip chip-accent px-2 py-0">{activeFilters[column].length}</span>}
</legend>
<div className="mt-2 max-h-44 space-y-0.5 overflow-y-auto pr-1">
{filterData.values.map((option) => {
const optLabel = isEn ? (VALUE_MAP_EN[option] || option) : isEs ? (VALUE_MAP_ES[option] || option) : isFr ? (VALUE_MAP_FR[option] || option) : isZh ? (VALUE_MAP_ZH[option] || option) : isDe ? (VALUE_MAP_DE[option] || option) : option;
return (
<label key={option} className="flex min-h-10 cursor-pointer items-center gap-3 rounded-lg px-2 text-sm text-muted transition-colors hover:bg-surface-2 hover:text-ink">
<input
type="checkbox"
checked={activeFilters[column]?.includes(option) || false}
onChange={() => handleFilterToggle(column, option)}
className="h-4 w-4 shrink-0 cursor-pointer accent-[var(--accent)]"
/>
{optLabel}
</label>
);
})}
</div>
</fieldset>
);
})}
</div>
);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10 sm:pt-12" aria-label={isEn ? "Boards" : isEs ? "Placas" : isFr ? "Cartes" : isZh ? "开发板" : isDe ? "Boards" : "Placas"}>
<div className="grid gap-8 lg:grid-cols-[17rem_1fr] lg:gap-10">
<aside className="lg:sticky lg:top-28 lg:self-start">
<details className="panel" open={filtrosAbertos} onToggle={(e) => setFiltrosAbertos(e.currentTarget.open)}>
<summary className="flex min-h-12 cursor-pointer list-none items-center justify-between gap-3 px-5 py-3 lg:cursor-default">
<span className="flex items-center gap-2 text-sm font-semibold text-ink">
<SlidersHorizontal className="h-4 w-4 text-accent" aria-hidden="true" />
{isEn ? "Filters" : isEs ? "Filtros" : isFr ? "Filtres" : isZh ? "筛选" : isDe ? "Filter" : "Filtros"}
{activeFilterCount > 0 && <span className="chip chip-accent px-2 py-0">{activeFilterCount}</span>}
</span>
{activeFilterCount > 0 && (
<button
type="button"
onClick={(e) => {
e.preventDefault();
clearFilters();
}}
className="text-sm font-medium text-accent hover:text-accent-strong"
>
{isEn ? "Clear" : isEs ? "Limpiar" : isFr ? "Effacer" : isZh ? "清除" : isDe ? "Zurücksetzen" : "Limpar"}
</button>
)}
</summary>
<div className="border-t border-line p-5 lg:max-h-[calc(100vh-11rem)] lg:overflow-y-auto">{filtros}</div>
</details>
</aside>
<div>
<p role="status" aria-live="polite" className="text-sm text-muted">
<strong className="font-semibold text-ink">{filteredBoards.length}</strong>{" "}
{isEn
? filteredBoards.length === 1
? "board found"
: "boards found"
: isEs
? filteredBoards.length === 1
? "placa encontrada"
: "placas encontradas"
: isFr
? filteredBoards.length === 1
? "carte trouvée"
: "cartes trouvées"
: isZh ? "款开发板" : isDe
? filteredBoards.length === 1
? "Board gefunden"
: "Boards gefunden"
: filteredBoards.length === 1
? "placa encontrada"
: "placas encontradas"}
</p>
{filteredBoards.length === 0 ? (
<div className="card mt-4 px-6 py-14 text-center">
<Search className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h2 className="mt-4 font-display text-xl font-semibold text-ink">
{isEn ? "No boards match these filters" : isEs ? "Ninguna placa coincide con estos filtros" : isFr ? "Aucune carte ne correspond à ces filtres" : isZh ? "没有符合这些筛选条件的开发板" : isDe ? "Keine Boards entsprechen diesen Filtern" : "Nenhuma placa com esses filtros"}
</h2>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
{isEn
? "Remove some filters or search by another name."
: isEs
? "Elimine algunos filtros o busque por otro nombre."
: isFr
? "Supprimez certains filtres ou recherchez un autre nom."
: isZh ? "请去掉一些筛选条件,或换个名称搜索。" : isDe
? "Entfernen Sie einige Filter oder suchen Sie nach einem anderen Namen."
: "Remova alguns filtros ou busque por outro nome."}
</p>
<button type="button" onClick={clearFilters} className="btn btn-primary mt-6">
{isEn ? "Clear filters" : isEs ? "Limpiar filtros" : isFr ? "Effacer les filtres" : isZh ? "清除筛选" : isDe ? "Filter zurücksetzen" : "Limpar filtros"}
</button>
</div>
) : (
<div className="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{filteredBoards.map((board, index) => (
<BoardCard key={index} board={board} />
))}
</div>
)}
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
+177
View File
@@ -0,0 +1,177 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isEn ? "Compare ESP32 Series: Side-by-Side Table" : isEs ? "Comparar series ESP32: tabla comparativa" : isFr ? "Comparer les séries ESP32 : tableau comparatif" : isZh ? "ESP32 系列对比" : isDe ? "ESP32-Serien vergleichen: Vergleichstabelle" : "Comparar séries ESP32",
descricao: isEn
? "Compare up to four ESP32 series side by side: processor, Wi-Fi, Bluetooth, memory, GPIO, peripherals, and hardware security, with official datasheet data."
: isEs
? "Compare hasta cuatro series de ESP32 frente a frente: procesador, Wi-Fi, Bluetooth, memoria, GPIO, periféricos y seguridad en hardware, con datos de hojas de datos oficiales."
: isFr
? "Comparez jusqu'à quatre séries d'ESP32 côte à côte : processeur, Wi-Fi, Bluetooth, mémoire, GPIO, périphériques et sécurité matérielle, avec les données des fiches techniques officielles."
: isZh ? "最多并排对比四个 ESP32 系列:处理器、Wi-Fi、蓝牙、内存、GPIO、外设和硬件安全,数据来自官方数据手册。" : isDe
? "Vergleichen Sie bis zu vier ESP32-Serien nebeneinander: Prozessor, Wi-Fi, Bluetooth, Speicher, GPIO, Peripherie und Hardware-Sicherheit mit Daten aus offiziellen Datenblättern."
: "Compare até quatro séries de ESP32 lado a lado: processador, Wi-Fi, Bluetooth, memória, GPIO, periféricos e segurança em hardware, com os dados dos datasheets oficiais.",
caminho: "/comparacao",
locale,
keywords: isEn
? ["compare ESP32", "ESP32 vs ESP32-S3", "ESP32 comparison table", "which ESP32 is best"]
: isEs
? ["comparar ESP32", "ESP32 vs ESP32-S3", "tabla comparativa ESP32", "cuál ESP32 es mejor"]
: isFr
? ["comparer ESP32", "ESP32 vs ESP32-S3", "tableau comparatif ESP32", "quel ESP32 choisir"]
: isZh ? ["ESP32 对比", "ESP32 vs ESP32-S3", "ESP32 对比表", "哪款 ESP32 最好"] : isDe
? ["ESP32 vergleichen", "ESP32 vs ESP32-S3", "ESP32 Vergleichstabelle", "welcher ESP32 ist der beste"]
: ["comparar ESP32", "ESP32 vs ESP32-S3", "tabela comparativa ESP32", "qual ESP32 é melhor"],
});
}
const faqsPt = [
{
pergunta: "Como comparar microcontroladores ESP32 lado a lado?",
resposta: "O comparador do ESPDocs permite selecionar até quatro séries simultaneamente para confrontar arquitetura, frequência de clock, memória SRAM/PSRAM, padrões de rádio (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), interfaces de periféricos e blocos de segurança em hardware.",
},
{
pergunta: "Qual a diferença entre o ESP32 clássico e o ESP32-S3?",
resposta: "O ESP32 clássico usa núcleos Xtensa LX6 e Bluetooth clássico/LE. O ESP32-S3 traz núcleos Xtensa LX7 com instruções vetoriais para inteligência artificial (TinyML), USB nativo OTG, mais GPIOs (45 contra 36) e Bluetooth 5.0 LE.",
},
{
pergunta: "Qual a diferença entre ESP32-C3 e ESP32-C6?",
resposta: "O ESP32-C3 é um microcontrolador RISC-V com Wi-Fi 4 e Bluetooth 5 LE. O ESP32-C6 evolui para Wi-Fi 6 (802.11ax), Bluetooth 5.4 LE, rádio IEEE 802.15.4 para Zigbee 3.0 e Thread 1.3, além de coprocessador de ultrabaixo consumo.",
},
];
const faqsEn = [
{
pergunta: "How to compare ESP32 microcontrollers side by side?",
resposta: "The ESPDocs comparator lets you select up to four series simultaneously to compare architecture, clock speed, SRAM/PSRAM memory, radio standards (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), peripheral interfaces, and hardware security blocks.",
},
{
pergunta: "What is the difference between classic ESP32 and ESP32-S3?",
resposta: "The classic ESP32 uses Xtensa LX6 cores and legacy Bluetooth/LE. The ESP32-S3 brings Xtensa LX7 cores with vector instructions for AI (TinyML), native USB OTG, more GPIOs (45 vs 36), and Bluetooth 5.0 LE.",
},
{
pergunta: "What is the difference between ESP32-C3 and ESP32-C6?",
resposta: "The ESP32-C3 is a RISC-V microcontroller with Wi-Fi 4 and Bluetooth 5 LE. The ESP32-C6 upgrades to Wi-Fi 6 (802.11ax), Bluetooth 5.4 LE, IEEE 802.15.4 radio for Zigbee 3.0 and Thread 1.3, plus an ultra-low-power coprocessor.",
},
];
const faqsEs = [
{
pergunta: "¿Cómo comparar microcontroladores ESP32 frente a frente?",
resposta: "El comparador de ESPDocs le permite seleccionar hasta cuatro series simultáneamente para cotejar arquitectura, frecuencia de reloj, memoria SRAM/PSRAM, estándares de radio (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), interfaces de periféricos y bloques de seguridad en hardware.",
},
{
pergunta: "¿Cuál es la diferencia entre el ESP32 clásico y el ESP32-S3?",
resposta: "El ESP32 clásico utiliza núcleos Xtensa LX6 y Bluetooth clásico/LE. El ESP32-S3 incorpora núcleos Xtensa LX7 con instrucciones vectoriales para inteligencia artificial (TinyML), USB nativo OTG, más GPIOs (45 frente a 36) y Bluetooth 5.0 LE.",
},
{
pergunta: "¿Cuál es la diferencia entre ESP32-C3 y ESP32-C6?",
resposta: "El ESP32-C3 es un microcontrolador RISC-V con Wi-Fi 4 y Bluetooth 5 LE. El ESP32-C6 evoluciona a Wi-Fi 6 (802.11ax), Bluetooth 5.4 LE, radio IEEE 802.15.4 para Zigbee 3.0 y Thread 1.3, además de un coprocesador de consumo ultrabajo.",
},
];
const faqsFr = [
{
pergunta: "Comment comparer les microcontrôleurs ESP32 côte à côte ?",
resposta: "Le comparateur d'ESPDocs vous permet de sélectionner jusqu'à quatre séries simultanément pour confronter architecture, fréquence d'horloge, mémoire SRAM/PSRAM, normes radio (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), interfaces de périphériques et blocs de sécurité matérielle.",
},
{
pergunta: "Quelle est la différence entre l'ESP32 classique et l'ESP32-S3 ?",
resposta: "L'ESP32 classique utilise des cœurs Xtensa LX6 et le Bluetooth classique/LE. L'ESP32-S3 intègre des cœurs Xtensa LX7 avec instructions vectorielles pour l'intelligence artificielle (TinyML), l'USB natif OTG, davantage de GPIOs (45 contre 36) et le Bluetooth 5.0 LE.",
},
{
pergunta: "Quelle est la différence entre l'ESP32-C3 et l'ESP32-C6 ?",
resposta: "L'ESP32-C3 est un microcontrôleur RISC-V avec Wi-Fi 4 et Bluetooth 5 LE. L'ESP32-C6 évolue vers le Wi-Fi 6 (802.11ax), le Bluetooth 5.4 LE, une radio IEEE 802.15.4 pour Zigbee 3.0 et Thread 1.3, ainsi qu'un coprocesseur à ultra-faible consommation.",
},
];
const faqsDe = [
{
pergunta: "Wie lassen sich ESP32-Mikrocontroller im direkten Vergleich gegenüberstellen?",
resposta: "Der ESPDocs-Vergleich ermöglicht es Ihnen, bis zu vier Serien gleichzeitig auszuwählen, um Architektur, Taktfrequenz, SRAM/PSRAM-Speicher, Funkstandards (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), Peripherieschnittstellen und Hardware-Sicherheitsblöcke zu vergleichen.",
},
{
pergunta: "Was ist der Unterschied zwischen dem klassischen ESP32 und dem ESP32-S3?",
resposta: "Der klassische ESP32 nutzt Xtensa-LX6-Kerne und klassisches Bluetooth/LE. Der ESP32-S3 bietet Xtensa-LX7-Kerne mit Vektoranweisungen für künstliche Intelligenz (TinyML), natives USB-OTG, mehr GPIOs (45 gegenüber 36) und Bluetooth 5.0 LE.",
},
{
pergunta: "Was ist der Unterschied zwischen ESP32-C3 und ESP32-C6?",
resposta: "Der ESP32-C3 ist ein RISC-V-Mikrocontroller mit Wi-Fi 4 und Bluetooth 5 LE. Der ESP32-C6 erweitert dies um Wi-Fi 6 (802.11ax), Bluetooth 5.4 LE, ein IEEE-802.15.4-Funkmodul für Zigbee 3.0 und Thread 1.3 sowie einen extrem stromsparenden Coprozessor.",
},
];
const faqsZh = [
{
pergunta: "如何并排对比 ESP32 微控制器?",
resposta: "ESPDocs 对比工具可同时选择最多四个系列,对比架构、主频、SRAM/PSRAM 内存、无线标准(Wi-Fi 4/6、蓝牙 5/6、802.15.4)、外设接口以及硬件安全模块。",
},
{
pergunta: "经典 ESP32 与 ESP32-S3 有什么区别?",
resposta: "经典 ESP32 使用 Xtensa LX6 内核和传统蓝牙/BLE。ESP32-S3 采用带 AI(TinyML)向量指令的 Xtensa LX7 内核,提供原生 USB OTG、更多 GPIO(45 对 36)以及蓝牙 5.0 LE。",
},
{
pergunta: "ESP32-C3 与 ESP32-C6 有什么区别?",
resposta: "ESP32-C3 是支持 Wi-Fi 4 和蓝牙 5 LE 的 RISC-V 微控制器。ESP32-C6 升级为 Wi-Fi 6(802.11ax)、蓝牙 5.4 LE,并带有用于 Zigbee 3.0 和 Thread 1.3 的 IEEE 802.15.4 射频,以及一颗超低功耗协处理器。",
},
];
export default async function Layout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const faqs = isEn ? faqsEn : isEs ? faqsEs : isFr ? faqsFr : isZh ? faqsZh : isDe ? faqsDe : faqsPt;
const canonPath = isEn ? "/en/compare" : isEs ? "/es/comparacion" : isFr ? "/fr/comparaison" : isZh ? "/zh-CN/compare" : isDe ? "/de/vergleich" : "/comparacao";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isEn ? "ESP32 Series Comparator" : isEs ? "Comparador de series ESP32" : isFr ? "Comparateur de séries ESP32" : isZh ? "ESP32 系列对比工具" : isDe ? "ESP32-Serien-Vergleich" : "Comparador de Séries ESP32",
descricao: isEn
? "Technical comparison table to analyze specifications, pinouts, and features of multiple ESP32 series."
: isEs
? "Tabla comparativa técnica para analizar especificaciones, patillaje y características de múltiples series de ESP32."
: isFr
? "Tableau comparatif technique pour analyser les spécifications, le brochage et les fonctionnalités de plusieurs séries ESP32."
: isZh ? "用于分析多个 ESP32 系列的规格、引脚和功能的技术对比表。" : isDe
? "Technische Vergleichstabelle zur Analyse von Spezifikationen, Pinbelegungen und Merkmalen mehrerer ESP32-Serien."
: "Tabela comparativa técnica para analisar especificações, pinagens e recursos de múltiplas séries de ESP32.",
caminho: canonPath,
locale,
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEn ? "Home" : isEs ? "Inicio" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEn ? "/en" : isEs ? "/es" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: isEn ? "Compare Series" : isEs ? "Comparar series" : isFr ? "Comparer les séries" : isZh ? "系列对比" : isDe ? "Serien vergleichen" : "Comparar Séries", caminho: canonPath },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
+799
View File
@@ -0,0 +1,799 @@
"use client";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import { useEffect, useState, useMemo, Fragment } from "react";
import { usePathname } from "next/navigation";
import Link from "next/link";
import seriesDataPt from "@/public/series.json";
import seriesDataEn from "@/data/en/series.json";
import seriesDataEs from "@/data/es/series.json";
import seriesDataFr from "@/data/fr/series.json";
import seriesDataDe from "@/data/de/series.json";
import seriesDataZh from "@/data/zh-CN/series.json";
import { getLocalizedHref } from "@/i18n/links";
import { ArrowRight, ArrowUpRight, Check, ChevronDown, Scale } from "lucide-react";
const MIN_SERIES = 2;
const MAX_SERIES = 4;
/* Lê "seguranca.ecc" além de chaves simples. */
function valorDe(objeto, caminho) {
return caminho.split(".").reduce((atual, parte) => atual?.[parte], objeto);
}
const COMPARE_FIELDS_PT = [
{ category: "Geral", fields: [
{ key: "nome_completo", label: "Nome Completo" },
{ key: "descricao", label: "Descrição" },
]},
{ category: "Disponibilidade e Ferramentas", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF mínimo" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "encapsulamento", label: "Encapsulamento" },
{ key: "modulos", label: "Módulos disponíveis" },
]},
{ category: "Processador", fields: [
{ key: "arquitetura", label: "Arquitetura" },
{ key: "nucleos", label: "Núcleos" },
{ key: "frequencia", label: "Frequência" },
{ key: "coprocessador_ulp", label: "Coprocessador ULP" },
{ key: "aceleradores_ia", label: "Aceleradores de IA" },
]},
{ category: "Conectividade", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memória", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash Externa" },
{ key: "psram_externa", label: "PSRAM Externa" },
]},
{ category: "Periféricos Digitais", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Periféricos Analógicos", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch Capacitivo" },
{ key: "sensor_hall", label: "Sensor Hall" },
{ key: "sensor_temperatura", label: "Sensor de Temperatura" },
]},
{ category: "Segurança", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (curvas elípticas)" },
{ key: "seguranca.ecdsa", label: "ECDSA em hardware" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Assinatura Digital (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Gerador aleatório (RNG)" },
{ key: "seguranca.criptografia_flash", label: "Criptografia de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Proteção contra DPA" },
]},
{ category: "Interfaces Especiais", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Câmera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Especificações Ambientais", fields: [
{ key: "temperatura_operacao", label: "Temp. Operação" },
{ key: "temperatura_armazenamento", label: "Temp. Armazenamento" },
]},
];
const COMPARE_FIELDS_EN = [
{ category: "General", fields: [
{ key: "nome_completo", label: "Full Name" },
{ key: "descricao", label: "Description" },
]},
{ category: "Availability and Tools", fields: [
{ key: "esp_idf_minimo", label: "Minimum ESP-IDF" },
{ key: "arduino_core", label: "Arduino Core" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "encapsulamento", label: "Package" },
{ key: "modulos", label: "Available Modules" },
]},
{ category: "Processor", fields: [
{ key: "arquitetura", label: "Architecture" },
{ key: "nucleos", label: "Cores" },
{ key: "frequencia", label: "Frequency" },
{ key: "coprocessador_ulp", label: "ULP Coprocessor" },
{ key: "aceleradores_ia", label: "AI Accelerators" },
]},
{ category: "Connectivity", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memory", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "External Flash" },
{ key: "psram_externa", label: "External PSRAM" },
]},
{ category: "Digital Peripherals", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Analog Peripherals", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Capacitive Touch" },
{ key: "sensor_hall", label: "Hall Sensor" },
{ key: "sensor_temperatura", label: "Temperature Sensor" },
]},
{ category: "Security", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (elliptic curves)" },
{ key: "seguranca.ecdsa", label: "Hardware ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Digital Signature (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Random Generator (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Flash Encryption" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "DPA Protection" },
]},
{ category: "Special Interfaces", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Camera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Environmental Specifications", fields: [
{ key: "temperatura_operacao", label: "Operating Temp." },
{ key: "temperatura_armazenamento", label: "Storage Temp." },
]},
];
const COMPARE_FIELDS_ES = [
{ category: "General", fields: [
{ key: "nome_completo", label: "Nombre completo" },
{ key: "descricao", label: "Descripción" },
]},
{ category: "Disponibilidad y herramientas", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF mínimo" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Depuración / JTAG" },
{ key: "encapsulamento", label: "Encapsulado" },
{ key: "modulos", label: "Módulos disponibles" },
]},
{ category: "Procesador", fields: [
{ key: "arquitetura", label: "Arquitectura" },
{ key: "nucleos", label: "Núcleos" },
{ key: "frequencia", label: "Frecuencia" },
{ key: "coprocessador_ulp", label: "Coprocesador ULP" },
{ key: "aceleradores_ia", label: "Aceleradores de IA" },
]},
{ category: "Conectividad", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memoria", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash externa" },
{ key: "psram_externa", label: "PSRAM externa" },
]},
{ category: "Periféricos digitales", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Depuración / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Periféricos analógicos", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch capacitivo" },
{ key: "sensor_hall", label: "Sensor Hall" },
{ key: "sensor_temperatura", label: "Sensor de temperatura" },
]},
{ category: "Seguridad", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (curvas elípticas)" },
{ key: "seguranca.ecdsa", label: "ECDSA en hardware" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Firma digital (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Generador aleatorio (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Cifrado de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Protección contra DPA" },
]},
{ category: "Interfaces especiales", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Cámara" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Especificaciones ambientales", fields: [
{ key: "temperatura_operacao", label: "Temp. operación" },
{ key: "temperatura_armazenamento", label: "Temp. almacenamiento" },
]},
];
const COMPARE_FIELDS_FR = [
{ category: "Général", fields: [
{ key: "nome_completo", label: "Nom complet" },
{ key: "descricao", label: "Description" },
]},
{ category: "Disponibilité et outils", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF minimum" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Débogage / JTAG" },
{ key: "encapsulamento", label: "Boîtier" },
{ key: "modulos", label: "Modules disponibles" },
]},
{ category: "Processeur", fields: [
{ key: "arquitetura", label: "Architecture" },
{ key: "nucleos", label: "Cœurs" },
{ key: "frequencia", label: "Fréquence" },
{ key: "coprocessador_ulp", label: "Coprocesseur ULP" },
{ key: "aceleradores_ia", label: "Accélérateurs IA" },
]},
{ category: "Connectivité", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Mémoire", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash externe" },
{ key: "psram_externa", label: "PSRAM externe" },
]},
{ category: "Périphériques numériques", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Débogage / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Périphériques analogiques", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch capacitif" },
{ key: "sensor_hall", label: "Capteur Hall" },
{ key: "sensor_temperatura", label: "Capteur de température" },
]},
{ category: "Sécurité", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (courbes elliptiques)" },
{ key: "seguranca.ecdsa", label: "ECDSA matériel" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Signature numérique (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Générateur aléatoire (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Chiffrement de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Protection contre DPA" },
]},
{ category: "Interfaces spéciales", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Caméra" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Spécifications environnementales", fields: [
{ key: "temperatura_operacao", label: "Temp. de fonctionnement" },
{ key: "temperatura_armazenamento", label: "Temp. de stockage" },
]},
];
const COMPARE_FIELDS_DE = [
{ category: "Allgemein", fields: [
{ key: "nome_completo", label: "Vollständiger Name" },
{ key: "descricao", label: "Beschreibung" },
]},
{ category: "Verfügbarkeit und Werkzeuge", fields: [
{ key: "esp_idf_minimo", label: "Mindest-ESP-IDF" },
{ key: "arduino_core", label: "Arduino-Core" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "encapsulamento", label: "Gehäuse" },
{ key: "modulos", label: "Verfügbare Module" },
]},
{ category: "Prozessor", fields: [
{ key: "arquitetura", label: "Architektur" },
{ key: "nucleos", label: "Kerne" },
{ key: "frequencia", label: "Taktfrequenz" },
{ key: "coprocessador_ulp", label: "ULP-Coprozessor" },
{ key: "aceleradores_ia", label: "KI-Beschleuniger" },
]},
{ category: "Konnektivität", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Speicher", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC-SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Externer Flash" },
{ key: "psram_externa", label: "Externer PSRAM" },
]},
{ category: "Digitale Peripherie", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Analoge Peripherie", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Kapazitiver Touch" },
{ key: "sensor_hall", label: "Hall-Sensor" },
{ key: "sensor_temperatura", label: "Temperatursensor" },
]},
{ category: "Sicherheit", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (Elliptische Kurven)" },
{ key: "seguranca.ecdsa", label: "Hardware-ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Digitale Signatur (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Zufallsgenerator (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Flash-Verschlüsselung" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "DPA-Schutz" },
]},
{ category: "Spezielle Schnittstellen", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Kamera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Umgebungsbedingungen", fields: [
{ key: "temperatura_operacao", label: "Betriebstemp." },
{ key: "temperatura_armazenamento", label: "Lagertemp." },
]},
];
const COMPARE_FIELDS_ZH = [
{ category: "概览", fields: [
{ key: "nome_completo", label: "完整名称" },
{ key: "descricao", label: "描述" },
]},
{ category: "可用性与工具", fields: [
{ key: "esp_idf_minimo", label: "最低 ESP-IDF 版本" },
{ key: "arduino_core", label: "Arduino 核心" },
{ key: "depuracao", label: "调试 / JTAG" },
{ key: "encapsulamento", label: "封装" },
{ key: "modulos", label: "可用模组" },
]},
{ category: "处理器", fields: [
{ key: "arquitetura", label: "架构" },
{ key: "nucleos", label: "内核" },
{ key: "frequencia", label: "频率" },
{ key: "coprocessador_ulp", label: "ULP 协处理器" },
{ key: "aceleradores_ia", label: "AI 加速器" },
]},
{ category: "无线连接", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "蓝牙" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "以太网" },
]},
{ category: "内存", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "外部闪存" },
{ key: "psram_externa", label: "外部 PSRAM" },
]},
{ category: "数字外设", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "调试 / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "模拟外设", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "电容触摸" },
{ key: "sensor_hall", label: "霍尔传感器" },
{ key: "sensor_temperatura", label: "温度传感器" },
]},
{ category: "安全", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC(椭圆曲线)" },
{ key: "seguranca.ecdsa", label: "硬件 ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "数字签名(DS)" },
{ key: "seguranca.key_manager", label: "密钥管理器" },
{ key: "seguranca.rng", label: "随机数发生器(TRNG)" },
{ key: "seguranca.criptografia_flash", label: "闪存加密" },
{ key: "seguranca.secure_boot", label: "安全启动" },
{ key: "seguranca.protecao_dpa", label: "DPA 防护" },
]},
{ category: "特殊接口", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "摄像头" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "以太网 MAC" },
]},
{ category: "环境规格", fields: [
{ key: "temperatura_operacao", label: "工作温度" },
{ key: "temperatura_armazenamento", label: "存储温度" },
]},
];
export default function Comparacao() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const currentLocale = isEs ? "es" : isEn ? "en" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const seriesData = isEs ? seriesDataEs : isEn ? seriesDataEn : isFr ? seriesDataFr : isZh ? seriesDataZh : isDe ? seriesDataDe : seriesDataPt;
const compareFields = isEs ? COMPARE_FIELDS_ES : isEn ? COMPARE_FIELDS_EN : isFr ? COMPARE_FIELDS_FR : isZh ? COMPARE_FIELDS_ZH : isDe ? COMPARE_FIELDS_DE : COMPARE_FIELDS_PT;
const [selectedSeries, setSelectedSeries] = useState(["ESP32", "ESP32-S3"]);
const [soDiferencas, setSoDiferencas] = useState(false);
const [collapsedCategories, setCollapsedCategories] = useState(() => ({
[isEs ? "Interfaces especiales" : isEn ? "Special Interfaces" : isFr ? "Interfaces spéciales" : isZh ? "特殊接口" : isDe ? "Spezielle Schnittstellen" : "Interfaces Especiais"]: true,
[isEs ? "Especificaciones ambientales" : isEn ? "Environmental Specifications" : isFr ? "Spécifications environnementales" : isZh ? "环境规格" : isDe ? "Umgebungsbedingungen" : "Especificações Ambientais"]: true,
}));
const series = Object.entries(seriesData);
// O seletor envia as séries finalistas em ?chips=ESP32-S3,ESP32-C6.
useEffect(() => {
const chips = new URLSearchParams(window.location.search).get("chips");
if (!chips) return;
const validas = [...new Set(chips.split(","))].filter((k) => seriesData[k]).slice(0, MAX_SERIES);
if (validas.length >= MIN_SERIES) setSelectedSeries(validas);
}, [seriesData]);
const toggleSeries = (seriesKey) => {
if (selectedSeries.includes(seriesKey)) {
if (selectedSeries.length > MIN_SERIES) setSelectedSeries(selectedSeries.filter((s) => s !== seriesKey));
} else if (selectedSeries.length < MAX_SERIES) {
setSelectedSeries([...selectedSeries, seriesKey]);
}
};
const toggleCategory = (category) => {
setCollapsedCategories({ ...collapsedCategories, [category]: !collapsedCategories[category] });
};
const renderValue = (value) => {
if (!value || value === "Não" || value === "No" || value === "Non" || (value === "Nein" || value === "否")) return <span className="text-muted">{isEs || isEn ? "No" : isFr ? "Non" : isZh ? "否" : isDe ? "Nein" : "Não"}</span>;
if (value === "Sim" || value === "Yes" || value === "Sí" || value === "Oui" || (value === "Ja" || value === "是")) {
return (
<span className="inline-flex items-center gap-1.5 font-medium text-ok">
<Check className="h-4 w-4" aria-hidden="true" />
{isEs ? "Sí" : isEn ? "Yes" : isFr ? "Oui" : isZh ? "是" : isDe ? "Ja" : "Sim"}
</span>
);
}
return <span className="font-medium text-ink">{value}</span>;
};
const valores = (key) => selectedSeries.map((k) => String(valorDe(seriesData[k], key) ?? (isEs || isEn ? "No" : isFr ? "Non" : isZh ? "否" : isDe ? "Nein" : "Não")));
const diferem = (key) => new Set(valores(key)).size > 1;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Comparador" : isEn ? "Comparator" : isFr ? "Comparateur" : isZh ? "对比工具" : isDe ? "Vergleich" : "Comparador" }]}
icon={Scale}
label={isEs ? "Hasta cuatro series lado a lado" : isEn ? "Up to four series side by side" : isFr ? "Jusqu'à quatre séries côte à côte" : isZh ? "最多四个系列并排对比" : isDe ? "Bis zu vier Serien im Vergleich" : "Até quatro séries lado a lado"}
title={isEs ? "Comparador de series ESP32" : isEn ? "ESP32 Series Comparator" : isFr ? "Comparateur de séries ESP32" : isZh ? "系列对比工具" : isDe ? "ESP32-Serien-Vergleich" : "Comparador de séries"}
lede={
isEs
? "Ponga núcleos, radio, memoria, periféricos y seguridad en la misma tabla y vea lo que realmente cambia de un chip a otro."
: isEn
? "Put cores, radio, memory, peripherals, and security in the same table and see what really changes from chip to chip."
: isFr
? "Placez les cœurs, la radio, la mémoire, les périphériques et la sécurité dans le même tableau et voyez ce qui change réellement d'une puce à l'autre."
: isZh ? "把内核、无线、内存、外设和安全放进同一张表,看看芯片之间到底有什么不同。" : isDe
? "Stellen Sie Kerne, Funk, Speicher, Peripherie und Sicherheit in derselben Tabelle gegenüber und sehen Sie, was sich wirklich von Chip zu Chip ändert."
: "Coloque núcleos, rádio, memória, periféricos e segurança na mesma tabela e veja o que realmente muda de um chip para outro."
}
/>
<section className="shell pt-10 sm:pt-12" aria-labelledby="escolha-titulo">
<div className="panel p-5 sm:p-7">
<div className="flex flex-wrap items-end justify-between gap-3">
<div>
<h2 id="escolha-titulo" className="text-base font-semibold text-ink">
{isEs ? (
<>Elija de {MIN_SERIES} a {MAX_SERIES} series</>
) : isEn ? (
<>Choose {MIN_SERIES} to {MAX_SERIES} series</>
) : isFr ? (
<>Choisissez de {MIN_SERIES} à {MAX_SERIES} séries</>
) : isZh ? ( <>请选择 {MIN_SERIES} 到 {MAX_SERIES} 个系列</> ) : isDe ? (
<>Wählen Sie {MIN_SERIES} bis {MAX_SERIES} Serien</>
) : (
<>Escolha de {MIN_SERIES} a {MAX_SERIES} séries</>
)}
</h2>
<p role="status" aria-live="polite" className="mt-1 text-sm text-muted">
{isEs ? (
<>
{selectedSeries.length} de {MAX_SERIES} seleccionadas
{selectedSeries.length === MAX_SERIES && ". Elimine una para cambiar."}
</>
) : isEn ? (
<>
{selectedSeries.length} of {MAX_SERIES} selected
{selectedSeries.length === MAX_SERIES && ". Remove one to switch."}
</>
) : isFr ? (
<>
{selectedSeries.length} sur {MAX_SERIES} sélectionnées
{selectedSeries.length === MAX_SERIES && ". Supprimez-en une pour en changer."}
</>
) : isZh ? ( <>
已选 {selectedSeries.length} / {MAX_SERIES} 个{selectedSeries.length === MAX_SERIES && "。请先移除一个再更换。"}
</> ) : isDe ? (
<>
{selectedSeries.length} von {MAX_SERIES} ausgewählt
{selectedSeries.length === MAX_SERIES && ". Entfernen Sie eine zum Wechseln."}
</>
) : (
<>
{selectedSeries.length} de {MAX_SERIES} selecionadas
{selectedSeries.length === MAX_SERIES && ". Remova uma para trocar."}
</>
)}
</p>
</div>
</div>
<div className="mt-4 flex flex-wrap gap-2">
{series.map(([key]) => {
const marcada = selectedSeries.includes(key);
const bloqueada = !marcada && selectedSeries.length >= MAX_SERIES;
return (
<button
key={key}
type="button"
onClick={() => toggleSeries(key)}
aria-pressed={marcada}
aria-disabled={bloqueada}
className={`chip-btn ${bloqueada ? "opacity-50" : ""}`}
>
{marcada && <Check className="h-4 w-4" aria-hidden="true" />}
{key}
</button>
);
})}
</div>
</div>
</section>
<section className="shell mt-8" aria-labelledby="tabela-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="tabela-titulo" className="text-base font-semibold text-ink">
{isEs ? "Especificaciones" : isEn ? "Specifications" : isFr ? "Spécifications" : isZh ? "规格" : isDe ? "Spezifikationen" : "Especificações"}
</h2>
<label className="flex min-h-11 cursor-pointer items-center gap-2.5 text-sm font-medium text-ink-soft">
<input
type="checkbox"
checked={soDiferencas}
onChange={(e) => setSoDiferencas(e.target.checked)}
className="h-5 w-5 cursor-pointer accent-[var(--accent)]"
/>
{isEs ? "Mostrar solo diferencias" : isEn ? "Show differences only" : isFr ? "Afficher uniquement les différences" : isZh ? "仅显示差异" : isDe ? "Nur Unterschiede anzeigen" : "Mostrar só as diferenças"}
</label>
</div>
<div className="panel mt-3 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full min-w-[30rem] border-collapse text-sm">
<caption className="sr-only">
{isEs ? (
<>Comparación de las series {selectedSeries.join(", ")}</>
) : isEn ? (
<>Comparison of series {selectedSeries.join(", ")}</>
) : isFr ? (
<>Comparaison des séries {selectedSeries.join(", ")}</>
) : isZh ? ( <>系列对比:{selectedSeries.join(", ")}</> ) : isDe ? (
<>Vergleich der Serien {selectedSeries.join(", ")}</>
) : (
<>Comparação das séries {selectedSeries.join(", ")}</>
)}
</caption>
<thead>
<tr className="border-b border-line bg-surface-2">
<th scope="col" className="sticky left-0 z-20 w-28 bg-surface-2 px-4 py-4 text-left font-semibold text-muted sm:w-52 sm:px-6">
{isEs ? "Especificación" : isEn ? "Specification" : isFr ? "Spécification" : isZh ? "规格项" : isDe ? "Spezifikation" : "Especificação"}
</th>
{selectedSeries.map((seriesKey) => (
<th key={seriesKey} scope="col" className="min-w-40 px-4 py-4 text-left sm:px-6">
<Link href={getLocalizedHref(`/series/${seriesKey}`, currentLocale)} className="inline-flex min-h-11 items-center gap-1 font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
<ArrowUpRight className="h-4 w-4 text-muted" aria-hidden="true" />
</Link>
</th>
))}
</tr>
</thead>
<tbody>
{compareFields.map(({ category, fields }) => {
const visiveis = soDiferencas ? fields.filter(({ key }) => diferem(key)) : fields;
if (soDiferencas && visiveis.length === 0) return null;
const isCollapsed = collapsedCategories[category] && !soDiferencas;
return (
<Fragment key={category}>
<tr className="border-y border-line bg-surface-2/60">
<th scope="rowgroup" colSpan={selectedSeries.length + 1} className="p-0 text-left">
<button
type="button"
onClick={() => toggleCategory(category)}
aria-expanded={!isCollapsed}
className="flex min-h-12 w-full cursor-pointer items-center justify-between gap-3 px-4 py-3 text-left font-semibold text-ink sm:px-6"
>
<span className="sticky left-4 sm:left-6">{category}</span>
<ChevronDown className={`h-4 w-4 shrink-0 text-muted transition-transform ${isCollapsed ? "" : "rotate-180"}`} aria-hidden="true" />
</button>
</th>
</tr>
{!isCollapsed &&
visiveis.map(({ key, label }) => (
<tr key={key} className="border-b border-line last:border-b-0 hover:bg-surface-2/50">
<th scope="row" className="sticky left-0 z-10 bg-surface px-4 py-3.5 text-left align-top font-medium text-muted sm:px-6">
{label}
</th>
{selectedSeries.map((seriesKey) => (
<td key={seriesKey} className="px-4 py-3.5 align-top sm:px-6">
{renderValue(valorDe(seriesData[seriesKey], key))}
</td>
))}
</tr>
))}
</Fragment>
);
})}
</tbody>
</table>
</div>
</div>
</section>
<section className="shell section" aria-labelledby="docs-titulo">
<h2 id="docs-titulo" className="section-title">
{isEs ? "Documentación oficial" : isEn ? "Official documentation" : isFr ? "Documentation officielle" : isZh ? "官方文档" : isDe ? "Offizielle Dokumentation" : "Documentação oficial"}
</h2>
<div className="mt-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
{selectedSeries.map((seriesKey) => {
const seriesItem = seriesData[seriesKey];
return (
<div key={seriesKey} className="card flex flex-col justify-between gap-5 p-5">
<Link href={getLocalizedHref(`/series/${seriesKey}`, currentLocale)} className="inline-flex min-h-11 items-center font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
</Link>
{seriesItem.datasheet ? (
<a href={seriesItem.datasheet} target="_blank" rel="noopener noreferrer" className="btn btn-ghost btn-sm">
{isEs ? "Datasheet oficial" : isEn ? "Official datasheet" : isFr ? "Fiche technique officielle" : isZh ? "官方数据手册" : isDe ? "Offizielles Datenblatt" : "Datasheet oficial"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> {isEs ? "(abre en una nueva pestaña)" : isEn ? "(opens in a new tab)" : isFr ? "(ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? "(öffnet in neuem Tab)" : "(abre em nova aba)"}</span>
</a>
) : (
<span className="text-sm text-muted">
{isEs ? "Datasheet aún no publicado" : isEn ? "Datasheet not yet published" : isFr ? "Fiche technique pas encore publiée" : isZh ? "数据手册尚未发布" : isDe ? "Datenblatt noch nicht veröffentlicht" : "Datasheet ainda não publicado"}
</span>
)}
</div>
);
})}
</div>
<div className="panel mt-10 flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">
{isEs ? "¿Desea probar en banco?" : isEn ? "Want to test on the bench?" : isFr ? "Envie de tester sur l'établi ?" : isZh ? "想在工作台上试试?" : isDe ? "Möchten Sie es auf dem Prüfplatz testen ?" : "Quer testar na bancada?"}
</h2>
<p className="mt-3 text-base text-muted">
{isEs
? "Vea las placas de desarrollo con patillaje, periféricos y enlace a la tienda oficial."
: isEn
? "Explore development boards with pinouts, peripherals, and official store links."
: isFr
? "Découvrez les cartes de développement avec brochage, périphériques et lien vers la boutique officielle."
: isZh ? "查看带引脚、外设和商店链接的开发板。" : isDe
? "Entdecken Sie die Entwicklungsboards mit Pinbelegung, Peripherie und Link zum offiziellen Store."
: "Veja as placas de desenvolvimento com pinagem, periféricos e link para a loja."}
</p>
</div>
<Link href={getLocalizedHref("/catalogo", currentLocale)} className="btn btn-primary shrink-0">
{isEs ? "Ver catálogo de placas" : isEn ? "View boards catalog" : isFr ? "Voir le catalogue de cartes" : isZh ? "查看开发板目录" : isDe ? "Board-Katalog ansehen" : "Ver catálogo de placas"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
</main>
<Footer />
</div>
);
}
+259
View File
@@ -0,0 +1,259 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: "ESP Component Registry & IDF Component Manager · ESPDocs",
descricao: isEs
? "Catálogo interactivo del ESP Component Registry: controladores de pantalla, LVGL, reconocimiento de voz ESP-SR, RainMaker, BSPs y generador de idf_component.yml."
: isEn
? "Official interactive catalog of the ESP Component Registry: display drivers, LVGL, ESP-SR voice recognition, RainMaker, BSPs, and idf_component.yml generator."
: isFr
? "Catalogue interactif du ESP Component Registry : pilotes d'écran, LVGL, reconnaissance vocale ESP-SR, RainMaker, BSPs et générateur d'idf_component.yml."
: isZh ? "官方交互式 ESP Component Registry 目录:显示屏驱动、LVGL、ESP-SR 语音识别、RainMaker、BSP 以及 idf_component.yml 生成器。" : isDe
? "Interaktiver Katalog der ESP Component Registry: Display-Treiber, LVGL, ESP-SR-Sprachkennung, RainMaker, BSPs und idf_component.yml-Generator."
: "Catálogo oficial e interativo do ESP Component Registry: drivers de displays, LVGL, reconhecimento de voz ESP-SR, RainMaker, BSPs e gerador de idf_component.yml.",
caminho: "/componentes",
locale,
keywords: isEs
? [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"componentes ESP32",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"bibliotecas ESP-IDF",
]
: isEn
? [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"ESP32 components",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"ESP-IDF libraries",
]
: isFr
? [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"composants ESP32",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"bibliothèques ESP-IDF",
]
: isZh ? ["ESP Component Registry", "IDF Component Manager", "idf_component.yml", "idf.py add-dependency", "ESP32 组件", "espressif esp_lvgl_port", "espressif esp_rainmaker", "espressif esp-sr", "ESP-IDF 库"] : isDe
? [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"ESP32 Komponenten",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"ESP-IDF Bibliotheken",
]
: [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"componentes ESP32",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"bibliotecas ESP-IDF",
],
});
}
const faqsPt = [
{
pergunta: "O que é o ESP Component Registry e o IDF Component Manager?",
resposta: "O ESP Component Registry (components.espressif.com) é o repositório oficial de pacotes modulares da Espressif. O IDF Component Manager é a ferramenta integrada ao ESP-IDF (a partir do v4.4 e padrão no v5.x+) que baixa, compila e resolve versões de dependências automaticamente a partir do manifesto idf_component.yml.",
},
{
pergunta: "Como adicionar um componente ao meu projeto ESP-IDF?",
resposta: "Você pode executar o comando 'idf.py add-dependency \"namespace/componente^versao\"' no terminal do projeto (por exemplo: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") ou editar diretamente o arquivo main/idf_component.yml.",
},
{
pergunta: "Qual a diferença entre usar o Component Registry e git submodules?",
resposta: "O Component Registry elimina a complexidade de gerenciar submódulos Git pesados e versões manuais. Ele oferece versionamento semântico (^ e ~), resolução automática de dependências transitivas e compilação modular sob demanda.",
},
{
pergunta: "Posso criar e publicar meus próprios componentes?",
resposta: "Sim, qualquer desenvolvedor ou empresa pode publicar componentes públicos ou privados no ESP Component Registry utilizando a ferramenta oficial Compote CLI (pip install idf-component-manager).",
},
];
const faqsEn = [
{
pergunta: "What is the ESP Component Registry and IDF Component Manager?",
resposta: "The ESP Component Registry (components.espressif.com) is the official central repository for modular Espressif packages. The IDF Component Manager is integrated into ESP-IDF (v4.4+ and default in v5.x+) to automatically download, compile, and resolve dependency versions from an idf_component.yml manifest.",
},
{
pergunta: "How to add a component to an ESP-IDF project?",
resposta: "You can run 'idf.py add-dependency \"namespace/component^version\"' in your project terminal (for example: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") or edit main/idf_component.yml directly.",
},
{
pergunta: "What is the difference between using Component Registry and git submodules?",
resposta: "The Component Registry eliminates the complexity of managing heavy Git submodules and manual tracking. It provides semantic versioning (^ and ~), automatic transitive dependency resolution, and modular on-demand compilation.",
},
{
pergunta: "Can I create and publish my own components?",
resposta: "Yes, any developer or company can publish public or private components to the ESP Component Registry using the official Compote CLI tool (pip install idf-component-manager).",
},
];
const faqsEs = [
{
pergunta: "¿Qué es el ESP Component Registry y el IDF Component Manager?",
resposta: "El ESP Component Registry (components.espressif.com) es el repositorio oficial de paquetes modulares de Espressif. El IDF Component Manager es la herramienta integrada en ESP-IDF (a partir de v4.4 y estándar en v5.x+) que descarga, compila y resuelve versiones de dependencias automáticamente desde el manifiesto idf_component.yml.",
},
{
pergunta: "¿Cómo agregar un componente a mi proyecto ESP-IDF?",
resposta: "Puede ejecutar el comando 'idf.py add-dependency \"namespace/componente^version\"' en la terminal del proyecto (por ejemplo: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") o editar directamente el archivo main/idf_component.yml.",
},
{
pergunta: "¿Cuál es la diferencia entre usar Component Registry y submódulos git?",
resposta: "El Component Registry elimina la complejidad de gestionar submódulos Git pesados y versiones manuales. Ofrece versionamiento semántico (^ y ~), resolución automática de dependencias transitivas y compilación modular bajo demanda.",
},
{
pergunta: "¿Puedo crear y publicar mis propios componentes?",
resposta: "Sí, cualquier desarrollador o empresa puede publicar componentes públicos o privados en el ESP Component Registry utilizando la herramienta oficial Compote CLI (pip install idf-component-manager).",
},
];
const faqsFr = [
{
pergunta: "Qu'est-ce que l'ESP Component Registry et l'IDF Component Manager ?",
resposta: "L'ESP Component Registry (components.espressif.com) est le dépôt officiel de paquets modulaires d'Espressif. L'IDF Component Manager est l'outil intégré à ESP-IDF (dès la v4.4 et standard en v5.x+) qui télécharge, compile et résout automatiquement les versions des dépendances à partir du manifeste idf_component.yml.",
},
{
pergunta: "Comment ajouter un composant à mon projet ESP-IDF ?",
resposta: "Vous pouvez exécuter la commande 'idf.py add-dependency \"namespace/composant^version\"' dans le terminal de votre projet (par exemple : idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") ou modifier directement le fichier main/idf_component.yml.",
},
{
pergunta: "Quelle est la différence entre le Component Registry et les sous-modules git ?",
resposta: "Le Component Registry élimine la complexité de gestion des sous-modules Git volumineux et des versions manuelles. Il apporte le versionnement sémantique (^ et ~), la résolution automatique des dépendances transitives et la compilation modulaire à la demande.",
},
{
pergunta: "Puis-je créer et publier mes propres composants ?",
resposta: "Oui, tout développeur ou entreprise peut publier des composants publics ou privés sur l'ESP Component Registry à l'aide de l'outil officiel Compote CLI (pip install idf-component-manager).",
},
];
const faqsDe = [
{
pergunta: "Was sind die ESP Component Registry und der IDF Component Manager?",
resposta: "Die ESP Component Registry (components.espressif.com) ist das offizielle Repository für modulare Espressif-Pakete. Der IDF Component Manager ist das in ESP-IDF (ab v4.4 und Standard in v5.x+) integrierte Werkzeug, das Abhängigkeiten anhand des idf_component.yml-Manifests automatisch herunterlädt, kompiliert und auflöst.",
},
{
pergunta: "Wie füge ich eine Komponente zu meinem ESP-IDF-Projekt hinzu?",
resposta: "Sie können den Befehl 'idf.py add-dependency \"namespace/komponente^version\"' im Projektterminal ausführen (z. B.: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") oder direkt die Datei main/idf_component.yml bearbeiten.",
},
{
pergunta: "Was ist der Unterschied zwischen der Component Registry und Git-Submodulen?",
resposta: "Die Component Registry beseitigt die Komplexität schwerfälliger Git-Submodule und manueller Versionsverwaltung. Sie bietet semantische Versionierung (^ und ~), automatische transitive Abhängigkeitsauflösung und modulare On-Demand-Kompilierung.",
},
{
pergunta: "Kann ich eigene Komponenten erstellen und veröffentlichen?",
resposta: "Ja, Entwickler und Unternehmen können öffentliche oder private Komponenten mit dem offiziellen Compote-CLI-Tool (pip install idf-component-manager) in der ESP Component Registry veröffentlichen.",
},
];
const faqsZh = [
{
pergunta: "什么是 ESP Component Registry 和 IDF Component Manager?",
resposta: "ESP Component Registry(components.espressif.com)是乐鑫模块化软件包的官方中央仓库。IDF Component Manager 集成在 ESP-IDF 中(v4.4+,v5.x+ 起默认启用),可根据 idf_component.yml 清单自动下载、编译并解析依赖版本。",
},
{
pergunta: "如何向 ESP-IDF 项目中添加组件?",
resposta: "可以在项目终端运行 'idf.py add-dependency \"namespace/component^version\"'(例如:idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\"),也可以直接编辑 main/idf_component.yml。",
},
{
pergunta: "使用 Component Registry 与 git 子模块有什么区别?",
resposta: "Component Registry 省去了管理笨重 Git 子模块和手动跟踪的麻烦。它提供语义化版本(^ 和 ~)、自动解析传递依赖,以及按需的模块化编译。",
},
{
pergunta: "我可以创建并发布自己的组件吗?",
resposta: "可以,任何开发者或公司都可以使用官方的 Compote CLI 工具(pip install idf-component-manager)向 ESP Component Registry 发布公开或私有组件。",
},
];
export default async function ComponentesLayout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const faqs = isEs ? faqsEs : isEn ? faqsEn : isFr ? faqsFr : isZh ? faqsZh : isDe ? faqsDe : faqsPt;
const canonPath = isEs ? "/es/componentes" : isEn ? "/en/components" : isFr ? "/fr/composants" : isZh ? "/zh-CN/components" : isDe ? "/de/komponenten" : "/componentes";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEs ? "Inicio" : isEn ? "Home" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: "ESP Component Registry", caminho: canonPath },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isEs
? "Hub de ESP Component Registry & Generador de Manifiesto"
: isEn
? "ESP Component Registry Hub & Manifest Builder"
: isFr
? "Hub de l'ESP Component Registry & Générateur de Manifeste"
: isZh ? "ESP Component Registry 中心与清单生成器" : isDe
? "ESP Component Registry Hub & Manifest-Generator"
: "Hub do ESP Component Registry & Construtor de Manifesto",
descricao: isEs
? "Catálogo curado y generador de manifiesto idf_component.yml para componentes modulares de ESP-IDF."
: isEn
? "Curated catalog and idf_component.yml manifest generator for modular ESP-IDF components."
: isFr
? "Catalogue sélectionné et générateur de manifeste idf_component.yml pour les composants modulaires d'ESP-IDF."
: isZh ? "ESP-IDF 模块化组件的精选目录与 idf_component.yml 清单生成器。" : isDe
? "Kuratierter Katalog und idf_component.yml-Manifest-Generator für modulare ESP-IDF-Komponenten."
: "Catálogo curado e gerador de manifesto idf_component.yml para componentes modulares do ESP-IDF.",
caminho: canonPath,
locale,
})
),
}}
/>
{children}
</>
);
}
+523
View File
@@ -0,0 +1,523 @@
"use client";
import { useState, useMemo } from "react";
import { usePathname } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import SectionHead from "@/components/SectionHead";
import * as componentesPt from "@/lib/componentRegistryData";
import * as componentesEn from "@/lib/data/en/componentes";
import * as componentesEs from "@/lib/data/es/componentes";
import * as componentesFr from "@/lib/data/fr/componentes";
import * as componentesDe from "@/lib/data/de/componentes";
import * as componentesZh from "@/lib/data/zh-CN/componentes";
import {
ArrowUpRight,
Box,
Brain,
Check,
CircuitBoard,
Cloud,
Copy,
Cpu,
Download,
HelpCircle,
Home,
Layers,
Monitor,
Plus,
Search,
ShieldCheck,
Terminal,
Trash2,
Wrench,
X,
} from "lucide-react";
const ICONES_CATEGORIA = {
ui_display: Monitor,
cloud_conectividade: Cloud,
audio_voz_ia: Brain,
smart_home_mesh: Home,
drivers_perifericos: Cpu,
bsp_placas: CircuitBoard,
sistema_utilitarios: Wrench,
};
export default function ComponentRegistryPage() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const { CATEGORIAS_COMPONENTES, COMPONENTES_REGISTRY, GUIA_COMPONENT_MANAGER } = isEs ? componentesEs : isEn ? componentesEn : isFr ? componentesFr : isZh ? componentesZh : isDe ? componentesDe : componentesPt;
const [busca, setBusca] = useState("");
const [categoriaAtiva, setCategoriaAtiva] = useState("todos");
const [chipFiltro, setChipFiltro] = useState("todos");
const [copiadoId, setCopiadoId] = useState(null);
const [manifestoCopiado, setManifestoCopiado] = useState(false);
// Componentes selecionados no construtor de idf_component.yml
const [componentesSelecionados, setComponentesSelecionados] = useState([
"espressif-esp_lvgl_port",
"espressif-led_indicator"
]);
// Lista de chips únicos para filtro
const chipsDisponiveis = ["todos", "ESP32", "ESP32-S3", "ESP32-C6", "ESP32-P4", "ESP32-H2", "ESP32-C3"];
// Filtragem dos componentes
const componentesFiltrados = useMemo(() => {
return COMPONENTES_REGISTRY.filter((comp) => {
const matchCategoria = categoriaAtiva === "todos" || comp.categoria === categoriaAtiva;
const matchChip = chipFiltro === "todos" || (comp.chips && comp.chips.includes(chipFiltro));
const matchBusca =
busca.trim() === "" ||
comp.name.toLowerCase().includes(busca.toLowerCase()) ||
comp.namespace.toLowerCase().includes(busca.toLowerCase()) ||
comp.titulo.toLowerCase().includes(busca.toLowerCase()) ||
comp.descricao.toLowerCase().includes(busca.toLowerCase()) ||
comp.tags.some((t) => t.toLowerCase().includes(busca.toLowerCase()));
return matchCategoria && matchChip && matchBusca;
});
}, [busca, categoriaAtiva, chipFiltro, COMPONENTES_REGISTRY]);
// Manipuladores de cópia
const copiarComando = (id, comando) => {
navigator.clipboard.writeText(comando);
setCopiadoId(id);
setTimeout(() => setCopiadoId(null), 2000);
};
const toggleSelecaoManifesto = (id) => {
setComponentesSelecionados((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
);
};
// Geração dinâmica do manifesto YAML
const manifestoYaml = useMemo(() => {
const selecionados = COMPONENTES_REGISTRY.filter((c) =>
componentesSelecionados.includes(c.id)
);
if (selecionados.length === 0) {
return isEs
? `# No hay componentes seleccionados.\n# Haga clic en "+ Agregar al manifiesto" en las tarjetas de abajo.`
: isEn
? `# No components selected.\n# Click "+ Add to Manifest" on the cards below.`
: isFr
? `# Aucun composant sélectionné.\n# Cliquez sur "+ Ajouter au manifeste" sur les cartes ci-dessous.`
: isZh ? `# 尚未选择组件。\n# 点击下方卡片中的“+ 添加到清单”。` : isDe
? `# Keine Komponenten ausgewählt.\n# Klicken Sie auf den Karten unten auf "+ Zum Manifest hinzufügen".`
: `# Nenhum componente selecionado.\n# Clique em "+ Adicionar ao Manifesto" nos cards abaixo.`;
}
let yaml = isEs
? `# main/idf_component.yml\n# Generado mediante ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/es/componentes)\n\ndependencies:\n`
: isEn
? `# main/idf_component.yml\n# Generated via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/en/components)\n\ndependencies:\n`
: isFr
? `# main/idf_component.yml\n# Généré via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/fr/composants)\n\ndependencies:\n`
: isZh ? `# main/idf_component.yml\n# 由 ESPDocs Component Hub 生成(https://espdocs.cienciaembarcada.com.br/zh-CN/components)\n\ndependencies:\n` : isDe
? `# main/idf_component.yml\n# Erstellt über den ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/de/komponenten)\n\ndependencies:\n`
: `# main/idf_component.yml\n# Gerado via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/componentes)\n\ndependencies:\n`;
selecionados.forEach((c) => {
yaml += ` ${c.namespace}/${c.name}: "${c.versao}"\n`;
});
return yaml;
}, [componentesSelecionados, COMPONENTES_REGISTRY, isEn, isEs, isFr, isDe, isZh]);
const copiarManifesto = () => {
navigator.clipboard.writeText(manifestoYaml);
setManifestoCopiado(true);
setTimeout(() => setManifestoCopiado(false), 2000);
};
const baixarManifesto = () => {
const blob = new Blob([manifestoYaml], { type: "text/yaml;charset=utf-8" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "idf_component.yml";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const limparFiltros = () => {
setBusca("");
setCategoriaAtiva("todos");
setChipFiltro("todos");
};
const totalFiltros = (busca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (chipFiltro !== "todos" ? 1 : 0);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Component Registry" : isEn ? "Component Registry" : isFr ? "Component Registry" : isZh ? "Component Registry" : isDe ? "Component Registry" : "Component Registry" }]}
icon={Box}
label="ESP-IDF Component Manager"
title="ESP Component Registry"
lede={
isEs
? "El catálogo oficial de paquetes reutilizables de Espressif para ESP-IDF. Elija controladores, voz y pilas industriales, copie el comando y genere el manifiesto del proyecto."
: isEn
? "Official Espressif catalog of reusable packages for ESP-IDF. Choose drivers, voice stacks, and industrial protocols, copy commands, and generate project manifests."
: isFr
? "Le catalogue officiel de paquets réutilisables d'Espressif pour ESP-IDF. Choisissez vos pilotes, piles vocales et protocoles industriels, copiez la commande et générez le manifeste du projet."
: isZh ? "乐鑫面向 ESP-IDF 的官方可复用软件包目录。选择驱动、语音和工业协议栈,复制命令并生成项目清单。" : isDe
? "Der offizielle Espressif-Katalog für wiederverwendbare Pakete für ESP-IDF. Wählen Sie Treiber, Sprach- und Industrieprotokolle, kopieren Sie den Befehl und erstellen Sie das Projektmanifest."
: "O catálogo oficial de pacotes reutilizáveis da Espressif para o ESP-IDF. Escolha drivers, voz e pilhas industriais, copie o comando e gere o manifesto do projeto."
}
>
<a href="https://components.espressif.com" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
{isEs ? "Abrir el registro oficial" : isEn ? "Open official registry" : isFr ? "Ouvrir le registre officiel" : isZh ? "打开官方注册中心" : isDe ? "Offizielles Repository öffnen" : "Abrir o registro oficial"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> {isEs ? "(abre en una nueva pestaña)" : isEn ? "(opens in a new tab)" : isFr ? "(ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? "(öffnet in neuem Tab)" : "(abre em nova aba)"}</span>
</a>
<a href="#manifesto-builder" className="btn btn-ghost">
{isEs ? "Generar idf_component.yml" : isEn ? "Generate idf_component.yml" : isFr ? "Générer idf_component.yml" : isZh ? "生成 idf_component.yml" : isDe ? "idf_component.yml erstellen" : "Gerar idf_component.yml"}
</a>
</PageHero>
<section className="shell pt-10 sm:pt-12" aria-label={isEs ? "Búsqueda y filtros" : isEn ? "Search and filters" : isFr ? "Recherche et filtres" : isZh ? "搜索与筛选" : isDe ? "Suche und Filter" : "Busca e filtros"}>
<div className="panel p-5 sm:p-6">
<div className="relative">
<label htmlFor="busca-componente" className="sr-only">
{isEs ? "Buscar por nombre, namespace o etiqueta" : isEn ? "Search by name, namespace, or tag" : isFr ? "Rechercher par nom, namespace ou tag" : isZh ? "按名称、命名空间或标签搜索" : isDe ? "Nach Name, Namespace oder Tag suchen" : "Buscar por nome, namespace ou tag"}
</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-componente"
type="search"
value={busca}
onChange={(e) => setBusca(e.target.value)}
placeholder={isEs ? "Buscar por nombre, namespace o etiqueta" : isEn ? "Search by name, namespace, or tag" : isFr ? "Rechercher par nom, namespace ou tag" : isZh ? "按名称、命名空间或标签搜索" : isDe ? "Nach Name, Namespace oder Tag suchen" : "Buscar por nome, namespace ou tag"}
autoComplete="off"
className="field pl-12 pr-4 text-base"
/>
</div>
<div className="mt-5">
<h2 className="text-sm font-semibold text-ink">{isEs ? "Categoría" : isEn ? "Category" : isFr ? "Catégorie" : isZh ? "类别" : isDe ? "Kategorie" : "Categoria"}</h2>
<div className="mt-3 flex flex-wrap gap-2">
{CATEGORIAS_COMPONENTES.map((cat) => {
const Icone = ICONES_CATEGORIA[cat.id] ?? Layers;
const contagem = cat.id === "todos" ? COMPONENTES_REGISTRY.length : COMPONENTES_REGISTRY.filter((c) => c.categoria === cat.id).length;
return (
<button key={cat.id} type="button" onClick={() => setCategoriaAtiva(cat.id)} aria-pressed={categoriaAtiva === cat.id} className="chip-btn">
<Icone className="h-4 w-4" aria-hidden="true" />
{cat.id === "todos" ? (isEs ? "Todos" : isEn ? "All" : isFr ? "Tous" : isZh ? "全部" : isDe ? "Alle" : "Todos") : cat.nome.replace(/\s*\(.*\)/, "").split(",")[0].split(" &")[0]}
<span className="tabular-nums opacity-80">{contagem}</span>
</button>
);
})}
</div>
</div>
<div className="mt-5 border-t border-line pt-5">
<h2 className="text-sm font-semibold text-ink">{isEs ? "Chip compatible" : isEn ? "Compatible chip" : isFr ? "Puce compatible" : isZh ? "兼容芯片" : isDe ? "Kompatibler Chip" : "Chip compatível"}</h2>
<div className="mt-3 flex flex-wrap gap-2">
{chipsDisponiveis.map((chip) => (
<button key={chip} type="button" onClick={() => setChipFiltro(chip)} aria-pressed={chipFiltro === chip} className="chip-btn">
{chip === "todos" ? (isEs ? "Todos" : isEn ? "All" : isFr ? "Tous" : isZh ? "全部" : isDe ? "Alle" : "Todos") : chip}
</button>
))}
</div>
</div>
</div>
</section>
<section className="shell section pt-8 sm:pt-10" aria-labelledby="lista-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="lista-titulo" role="status" aria-live="polite" className="text-base font-semibold text-ink">
{componentesFiltrados.length} {componentesFiltrados.length === 1 ? (isEs ? "componente" : isEn ? "component" : isFr ? "composant" : isZh ? "个组件" : isDe ? "Komponente" : "componente") : (isEs ? "componentes" : isEn ? "components" : isFr ? "composants" : isZh ? "个组件" : isDe ? "Komponenten" : "componentes")}
</h2>
<div className="flex flex-wrap items-center gap-x-5 gap-y-1">
{totalFiltros > 0 && (
<button type="button" onClick={limparFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<X className="h-4 w-4" aria-hidden="true" />
{isEs ? "Limpiar filtros" : isEn ? "Clear filters" : isFr ? "Effacer les filtres" : isZh ? "清除筛选" : isDe ? "Filter zurücksetzen" : "Limpar filtros"}
</button>
)}
<a href="#manifesto-builder" className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
{isEs ? "Manifiesto:" : isEn ? "Manifest:" : isFr ? "Manifeste :" : isZh ? "清单:" : isDe ? "Manifest :" : "Manifesto:"} {componentesSelecionados.length} {componentesSelecionados.length === 1 ? (isEs ? "componente" : isEn ? "component" : isFr ? "composant" : isZh ? "个组件" : isDe ? "Komponente" : "componente") : (isEs ? "componentes" : isEn ? "components" : isFr ? "composants" : isZh ? "个组件" : isDe ? "Komponenten" : "componentes")}
</a>
</div>
</div>
{componentesFiltrados.length === 0 ? (
<div className="card mt-6 px-6 py-14 text-center">
<Box className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">
{isEs ? "No se encontraron componentes" : isEn ? "No components found" : isFr ? "Aucun composant trouvé" : isZh ? "未找到组件" : isDe ? "Keine Komponenten gefunden" : "Nenhum componente encontrado"}
</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
{isEs
? "Busque por un término más general o regrese a todas las categorías."
: isEn
? "Search for a more general term or return to all categories."
: isFr
? "Recherchez un terme plus général ou revenez à toutes les catégories."
: isZh ? "请搜索更通用的词,或返回全部类别。" : isDe
? "Suchen Sie nach einem allgemeineren Begriff oder kehren Sie zu allen Kategorien zurück."
: "Busque por um termo mais geral ou volte para todas as categorias."}
</p>
<button type="button" onClick={limparFiltros} className="btn btn-primary mt-6">
{isEs ? "Limpiar filtros" : isEn ? "Clear filters" : isFr ? "Effacer les filtres" : isZh ? "清除筛选" : isDe ? "Filter zurücksetzen" : "Limpar filtros"}
</button>
</div>
) : (
<div className="mt-6 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{componentesFiltrados.map((comp) => {
const selecionado = componentesSelecionados.includes(comp.id);
const cliCmd = `idf.py add-dependency "${comp.namespace}/${comp.name}${comp.versao}"`;
const foiCopiado = copiadoId === comp.id;
return (
<article key={comp.id} className={`card flex flex-col overflow-hidden ${selecionado ? "border-accent ring-2 ring-accent/20" : ""}`}>
<div className="flex-1 p-5 sm:p-6">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="flex flex-wrap items-center gap-2 text-xs text-muted">
{comp.namespace}/
{comp.oficial && (
<span className="chip chip-accent px-2 py-0">
<ShieldCheck className="h-3 w-3" aria-hidden="true" />
{isEs ? "Oficial" : isEn ? "Official" : isFr ? "Officiel" : isZh ? "官方" : isDe ? "Offiziell" : "Oficial"}
</span>
)}
</p>
<h3 className="mt-1 break-words font-display text-xl font-semibold tracking-[-0.03em] text-ink">{comp.name}</h3>
<p className="mt-0.5 text-sm font-medium text-accent">{comp.titulo}</p>
</div>
<span className="shrink-0 rounded-md border border-line bg-surface-2 px-2 py-1 font-mono text-xs text-ink-soft">{comp.versao}</span>
</div>
<p className="mt-3 line-clamp-3 text-sm leading-relaxed text-muted">{comp.descricao}</p>
<ul className="mt-4 flex flex-wrap gap-1.5">
{comp.tags.map((tag) => (
<li key={tag} className="chip">{tag}</li>
))}
</ul>
</div>
<div className="border-t border-line bg-surface-2/60 p-5 sm:px-6">
<button
type="button"
onClick={() => copiarComando(comp.id, cliCmd)}
className="code-panel flex w-full min-h-11 items-center justify-between gap-3 rounded-lg px-3 py-2 text-left font-mono text-xs transition-colors hover:border-white/30"
aria-label={isEs ? `Copiar comando para agregar ${comp.name}` : isEn ? `Copy command to add ${comp.name}` : isFr ? `Copier la commande pour ajouter ${comp.name}` : isZh ? `复制添加 ${comp.name} 的命令` : isDe ? `Befehl zum Hinzufügen von ${comp.name} kopieren` : `Copiar comando para adicionar ${comp.name}`}
>
<span className="truncate text-[#e9eef4]">{cliCmd}</span>
{foiCopiado ? <Check className="h-4 w-4 shrink-0 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4 shrink-0 text-[#a6afbd]" aria-hidden="true" />}
</button>
<p role="status" className="sr-only">{foiCopiado ? (isEs ? "Comando copiado" : isEn ? "Command copied" : isFr ? "Commande copiée" : isZh ? "命令已复制" : isDe ? "Befehl kopiert" : "Comando copiado") : ""}</p>
<p className="mt-3 text-xs text-muted">
<span className="font-medium text-ink-soft">Chips: </span>
{comp.chips.join(", ")}
</p>
</div>
<div className="flex items-center justify-between gap-2 border-t border-line p-4 sm:px-6">
<button
type="button"
onClick={() => toggleSelecaoManifesto(comp.id)}
aria-pressed={selecionado}
className={`btn btn-sm ${selecionado ? "btn-primary" : "btn-ghost"}`}
>
{selecionado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Plus className="h-4 w-4" aria-hidden="true" />}
{selecionado ? (isEs ? "En manifiesto" : isEn ? "In manifest" : isFr ? "Dans le manifeste" : isZh ? "已在清单中" : isDe ? "Im Manifest" : "No manifesto") : (isEs ? "Agregar al manifiesto" : isEn ? "Add to manifest" : isFr ? "Ajouter au manifeste" : isZh ? "添加到清单" : isDe ? "Zum Manifest hinzufügen" : "Adicionar ao manifesto")}
</button>
<a
href={comp.urlRegistry}
target="_blank"
rel="noopener noreferrer"
className="btn-icon inline-flex h-11 w-11 items-center justify-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-accent"
aria-label={isEs ? `Abrir ${comp.name} en el registro oficial (nueva pestaña)` : isEn ? `Open ${comp.name} in official registry (new tab)` : isFr ? `Ouvrir ${comp.name} sur le registre officiel (nouvel onglet)` : isZh ? `在官方注册中心打开 ${comp.name}(新标签页)` : isDe ? `${comp.name} in der offiziellen Registry öffnen (neuer Tab)` : `Abrir ${comp.name} no registro oficial (nova aba)`}
>
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</div>
</article>
);
})}
</div>
)}
</section>
<section id="manifesto-builder" className="shell scroll-mt-28 pb-16" aria-labelledby="manifesto-titulo">
<div className="panel p-6 sm:p-9">
<div className="flex flex-col justify-between gap-5 md:flex-row md:items-end">
<div className="max-w-2xl">
<p className="eyebrow">{isEs ? "Generador de manifiesto" : isEn ? "Manifest generator" : isFr ? "Générateur de manifeste" : isZh ? "清单生成器" : isDe ? "Manifest-Generator" : "Gerador de manifesto"}</p>
<h2 id="manifesto-titulo" className="section-title mt-3">
{isEs ? "Su idf_component.yml" : isEn ? "Your idf_component.yml" : isFr ? "Votre idf_component.yml" : isZh ? "你的 idf_component.yml" : isDe ? "Ihre idf_component.yml" : "Seu idf_component.yml"}
</h2>
<p className="mt-3 text-sm leading-relaxed text-muted">
{isEs ? (
<>Guarde el archivo en la carpeta <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> del proyecto y ESP-IDF descargará todas las bibliotecas durante la compilación.</>
) : isEn ? (
<>Save this file in your project&apos;s <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> folder and ESP-IDF will download all dependencies during build.</>
) : isFr ? (
<>Enregistrez le fichier dans le dossier <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> du projet et ESP-IDF téléchargera toutes les bibliothèques lors de la compilation.</>
) : isZh ? ( <>将文件保存到项目的 <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> 文件夹中,ESP-IDF 会在编译时下载所有库。</> ) : isDe ? (
<>Speichern Sie die Datei im Ordner <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> Ihres Projekts, und ESP-IDF lädt beim Build alle Abhängigkeiten herunter.</>
) : (
<>Salve o arquivo na pasta <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> do projeto e o ESP-IDF baixa todas as bibliotecas na compilação.</>
)}
</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<button type="button" onClick={copiarManifesto} className="btn btn-primary btn-sm">
{manifestoCopiado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
<span role="status">{manifestoCopiado ? (isEs ? "Copiado" : isEn ? "Copied" : isFr ? "Copié" : isZh ? "已复制" : isDe ? "Kopiert" : "Copiado") : (isEs ? "Copiar YAML" : isEn ? "Copy YAML" : isFr ? "Copier le YAML" : isZh ? "复制 YAML" : isDe ? "YAML kopieren" : "Copiar YAML")}</span>
</button>
<button type="button" onClick={baixarManifesto} className="btn btn-ghost btn-sm">
<Download className="h-4 w-4" aria-hidden="true" />
{isEs ? "Descargar .yml" : isEn ? "Download .yml" : isFr ? "Télécharger .yml" : isZh ? "下载 .yml" : isDe ? ".yml herunterladen" : "Baixar .yml"}
</button>
{componentesSelecionados.length > 0 && (
<button type="button" onClick={() => setComponentesSelecionados([])} className="btn btn-ghost btn-sm">
<Trash2 className="h-4 w-4" aria-hidden="true" />
{isEs ? "Limpiar" : isEn ? "Clear" : isFr ? "Effacer" : isZh ? "清除" : isDe ? "Leeren" : "Limpar"}
</button>
)}
</div>
</div>
<div className="code-panel mt-6">
<pre tabIndex={0} aria-label={isEs ? "Contenido de idf_component.yml" : isEn ? "Content of idf_component.yml" : isFr ? "Contenu de idf_component.yml" : isZh ? "idf_component.yml 的内容" : isDe ? "Inhalt von idf_component.yml" : "Conteúdo do idf_component.yml"} className="!text-sm"><code className="text-[#e9eef4]">{manifestoYaml}</code></pre>
</div>
{componentesSelecionados.length > 0 && (
<ul className="mt-5 flex flex-wrap items-center gap-2" aria-label={isEs ? "Componentes incluidos" : isEn ? "Included components" : isFr ? "Composants inclus" : isZh ? "已包含的组件" : isDe ? "Enthaltene Komponenten" : "Componentes incluídos"}>
{componentesSelecionados.map((id) => {
const c = COMPONENTES_REGISTRY.find((item) => item.id === id);
if (!c) return null;
return (
<li key={id} className="chip chip-accent gap-1 pr-1">
{c.name}
<button
type="button"
onClick={() => toggleSelecaoManifesto(id)}
className="-my-2 grid h-11 w-11 place-items-center rounded-full hover:bg-accent/15"
aria-label={isEs ? `Eliminar ${c.name} del manifiesto` : isEn ? `Remove ${c.name} from manifest` : isFr ? `Retirer ${c.name} du manifeste` : isZh ? `从清单中移除 ${c.name}` : isDe ? `${c.name} aus dem Manifest entfernen` : `Remover ${c.name} do manifesto`}
>
<X className="h-3.5 w-3.5" aria-hidden="true" />
</button>
</li>
);
})}
</ul>
)}
</div>
</section>
<section className="shell section border-t border-line pt-14" aria-labelledby="guia-titulo">
<SectionHead id="guia-titulo" eyebrow={isEs ? "Guía rápida" : isEn ? "Quick guide" : isFr ? "Guide rapide" : isZh ? "快速指南" : isDe ? "Kurzanleitung" : "Guia rápido"} title={GUIA_COMPONENT_MANAGER.titulo} lede={GUIA_COMPONENT_MANAGER.resumo} />
<ul className="mt-8 grid gap-3 md:grid-cols-2 lg:grid-cols-4">
{GUIA_COMPONENT_MANAGER.vantagens.map((v) => (
<li key={v.titulo} className="card p-5">
<h3 className="font-semibold text-ink">{v.titulo}</h3>
<p className="mt-2 text-sm leading-relaxed text-muted">{v.descricao}</p>
</li>
))}
</ul>
<h3 className="mt-12 flex items-center gap-2 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
<Terminal className="h-5 w-5 text-accent" aria-hidden="true" />
{isEs ? "Comandos esenciales" : isEn ? "Essential commands" : isFr ? "Commandes essentielles" : isZh ? "基本命令" : isDe ? "Wichtige Befehle" : "Comandos essenciais"}
</h3>
<ul className="mt-4 space-y-3">
{GUIA_COMPONENT_MANAGER.comandosCli.map((cmd, i) => (
<li key={cmd.exemplo} className="code-panel flex flex-col justify-between gap-3 p-4 md:flex-row md:items-center">
<div className="min-w-0">
<code className="block break-all font-mono text-sm text-[#5eead4]">$ {cmd.exemplo}</code>
<p className="mt-1 text-sm text-[#a6afbd]">{cmd.explicacao}</p>
</div>
<button
type="button"
onClick={() => copiarComando(`cmd-${i}`, cmd.exemplo)}
className="inline-flex min-h-11 shrink-0 items-center gap-1.5 self-start rounded-full border border-white/15 px-4 text-sm font-medium text-[#e9eef4] transition-colors hover:bg-white/10 md:self-auto"
>
{copiadoId === `cmd-${i}` ? <Check className="h-4 w-4 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `cmd-${i}` ? (isEs ? "Copiado" : isEn ? "Copied" : isFr ? "Copié" : isZh ? "已复制" : isDe ? "Kopiert" : "Copiado") : (isEs ? "Copiar" : isEn ? "Copy" : isFr ? "Copier" : isZh ? "复制" : isDe ? "Kopieren" : "Copiar")}
</button>
</li>
))}
</ul>
<div className="callout mt-8">
<h3 className="flex items-center gap-2 font-semibold text-ink">
<HelpCircle className="h-4 w-4 text-accent" aria-hidden="true" />
{isEs ? "Versionamiento semántico en ESP-IDF" : isEn ? "Semantic versioning in ESP-IDF" : isFr ? "Versionnement sémantique dans ESP-IDF" : isZh ? "ESP-IDF 中的语义化版本" : isDe ? "Semantische Versionierung in ESP-IDF" : "Versionamento semântico no ESP-IDF"}
</h3>
<ul className="mt-2 list-disc space-y-1.5 pl-5">
{isEs ? (
<>
<li><code>^1.2.0</code>: acepta actualizaciones menores y correcciones (1.2.1, 1.3.0), pero bloquea cambios importantes de API (2.0.0). <strong>Recomendado.</strong></li>
<li><code>~1.2.0</code>: acepta solo correcciones de errores (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: bloquea en esta versión exacta.</li>
<li><code>*</code>: acepta cualquier versión. Evite en producción.</li>
</>
) : isEn ? (
<>
<li><code>^1.2.0</code>: accepts minor updates and bug fixes (1.2.1, 1.3.0), but blocks breaking API changes (2.0.0). <strong>Recommended.</strong></li>
<li><code>~1.2.0</code>: accepts patch releases only (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: locks to this exact version.</li>
<li><code>*</code>: accepts any version. Avoid in production.</li>
</>
) : isFr ? (
<>
<li><code>^1.2.0</code>: accepte les mises à jour mineures et les correctifs (1.2.1, 1.3.0), mais bloque les changements majeurs d'API (2.0.0). <strong>Recommandé.</strong></li>
<li><code>~1.2.0</code>: accepte uniquement les correctifs de bugs (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: verrouille sur cette version exacte.</li>
<li><code>*</code>: accepte n'importe quelle version. À éviter en production.</li>
</>
) : isZh ? ( <>
<li><code>^1.2.0</code>:接受次版本更新和修复(1.2.1、1.3.0),但会阻止重大 API 变更(2.0.0)。<strong>推荐。</strong></li>
<li><code>~1.2.0</code>:只接受缺陷修复(1.2.1、1.2.5)。</li>
<li><code>1.2.0</code>:锁定到精确版本。</li>
<li><code>*</code>:接受任意版本。生产环境请避免。</li>
</> ) : isDe ? (
<>
<li><code>^1.2.0</code>: akzeptiert Minor-Updates und Bugfixes (1.2.1, 1.3.0), blockiert aber Breaking Changes (2.0.0). <strong>Empfohlen.</strong></li>
<li><code>~1.2.0</code>: akzeptiert nur Patch-Releases (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: bindet fest an diese Version.</li>
<li><code>*</code>: akzeptiert jede Version. In Produktion vermeiden.</li>
</>
) : (
<>
<li><code>^1.2.0</code>: aceita atualizações menores e correções (1.2.1, 1.3.0), mas bloqueia mudanças grandes de API (2.0.0). <strong>Recomendado.</strong></li>
<li><code>~1.2.0</code>: aceita só correções de bugs (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: trava na versão exata.</li>
<li><code>*</code>: aceita qualquer versão. Evite em produção.</li>
</>
)}
</ul>
</div>
</section>
</main>
<Footer />
</div>
);
}
+256
View File
@@ -0,0 +1,256 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isEs
? "Diagnóstico de errores comunes en ESP32: Guía profesional"
: isEn
? "Common ESP32 Errors & Diagnostics: Professional Guide"
: isFr
? "Diagnostic des erreurs courantes sur ESP32 : guide professionnel"
: isZh ? "ESP32 常见故障诊断:专业指南" : isDe
? "Diagnose häufiger ESP32-Fehler: Professioneller Leitfaden"
: "Diagnóstico de Erros Comuns no ESP32: Guia Profissional",
descricao: isEs
? "Guía técnica definitiva para identificar y solucionar Brownout, Guru Meditation, Task Watchdog, Stack Overflow, fugas de memoria y fallas de arranque en ESP32 (Arduino y ESP-IDF)."
: isEn
? "Definitive technical guide to identify and fix Brownout, Guru Meditation, Task Watchdog, Stack Overflow, memory leaks, and boot issues on ESP32 (Arduino & ESP-IDF)."
: isFr
? "Guide technique pour identifier et résoudre Brownout, Guru Meditation, Task Watchdog, Stack Overflow, fuites de mémoire et pannes de démarrage sur ESP32 (Arduino et ESP-IDF)."
: isZh ? "权威技术指南,用于识别并解决 ESP32(Arduino 与 ESP-IDF)上的 Brownout、Guru Meditation、Task Watchdog、栈溢出、内存泄漏和启动故障。" : isDe
? "Technischer Leitfaden zur Behebung von Brownout, Guru Meditation, Task Watchdog, Stack Overflow, Speicherlecks und Boot-Problemen beim ESP32 (Arduino & ESP-IDF)."
: "Guia técnico definitivo para identificar e resolver Brownout, Guru Meditation, Task Watchdog, Stack Overflow, vazamento de memória e falhas de boot no ESP32 (Arduino e ESP-IDF).",
caminho: "/diagnostico",
locale,
keywords: isEs
? [
"errores comunes ESP32",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"cómo depurar ESP32",
"ESP32 reiniciando en bucle",
"failed to connect to esp32",
]
: isEn
? [
"common ESP32 errors",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"how to debug ESP32",
"ESP32 bootloop rebooting",
"failed to connect to esp32",
]
: isFr
? [
"erreurs courantes ESP32",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"comment déboguer ESP32",
"ESP32 redémarre en boucle",
"failed to connect to esp32",
]
: isZh ? ["ESP32 常见错误", "brownout detector was triggered", "guru meditation error", "task watchdog got triggered", "stack canary watchpoint triggered", "如何调试 ESP32", "ESP32 反复重启", "failed to connect to esp32"] : isDe
? [
"häufige ESP32-Fehler",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"ESP32 debuggen",
"ESP32 Bootloop Neustart",
"failed to connect to esp32",
]
: [
"erros comuns ESP32",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"como debugar ESP32",
"ESP32 reiniciando em loop",
"failed to connect to esp32",
],
});
}
const faqsPt = [
{
pergunta: "O que causa o erro 'Brownout detector was triggered' no ESP32?",
resposta: "Ocorre quando a tensão no pino 3V3 cai abaixo de 2.8V ~ 2.43V devido a picos rápidos de corrente do rádio Wi-Fi/BLE (superando 500mA), cabos USB finos ou regulador LDO inadequado. A solução de engenharia envolve adicionar capacitores Low-ESR de 10µF a 100µF próximos ao VCC e usar LDOs robustos de 600mA+.",
},
{
pergunta: "Como resolver o 'Guru Meditation Error (LoadProhibited)'?",
resposta: "LoadProhibited indica tentativa de acessar um ponteiro nulo (NULL) ou inválido na memória. A solução consiste em usar o Espressif Exception Decoder ou addr2line para localizar a linha exata no código e implementar validações defensivas como if (ponteiro != NULL).",
},
{
pergunta: "Por que o Task Watchdog Timer (TWDT) dispara no FreeRTOS?",
resposta: "O TWDT dispara quando uma tarefa de prioridade maior monopoliza a CPU em um loop bloqueante (ex: while(1) sem vTaskDelay), impedindo a tarefa IDLE de alimentar o watchdog do sistema operacional.",
},
{
pergunta: "Por que conexões HTTPS e TLS falham com código -0x2700 no ESP32?",
resposta: "Porque ao ligar, o ESP32 inicia o relógio interno no ano de 1970. O validador de certificados TLS considera o certificado do servidor inválido por estar no 'futuro'. Sincronizar o relógio via SNTP (configTime) antes da conexão resolve o problema.",
},
];
const faqsEn = [
{
pergunta: "What causes 'Brownout detector was triggered' on ESP32?",
resposta: "It occurs when the 3V3 rail drops below 2.8V ~ 2.43V during rapid Wi-Fi/BLE radio current spikes (often exceeding 500mA), caused by thin USB cables or an undersized LDO regulator. The engineering solution involves placing 10µF to 100µF Low-ESR bypass capacitors near VCC and using 600mA+ robust LDO regulators.",
},
{
pergunta: "How to resolve 'Guru Meditation Error (LoadProhibited)'?",
resposta: "LoadProhibited indicates an attempt to read from or write to a null (NULL) or invalid memory address. The fix involves using the Espressif Exception Decoder or addr2line to pinpoint the source line and applying defensive checks such as if (ptr != NULL).",
},
{
pergunta: "Why does the Task Watchdog Timer (TWDT) trigger in FreeRTOS?",
resposta: "The TWDT triggers when a high-priority task monopolizes the CPU in a tight blocking loop (e.g. while(1) without vTaskDelay), starving the lower-priority IDLE task that feeds the operating system watchdog.",
},
{
pergunta: "Why do HTTPS and TLS connections fail with error -0x2700 on ESP32?",
resposta: "On boot, the ESP32 internal system clock starts at epoch year 1970. The TLS certificate validator rejects the server certificate because its validity dates appear in the distant 'future'. Synchronizing time via SNTP (configTime) prior to initiating TLS connections resolves the issue.",
},
];
const faqsEs = [
{
pergunta: "¿Qué causa el error 'Brownout detector was triggered' en el ESP32?",
resposta: "Ocurre cuando la tensión en el pin 3V3 cae por debajo de 2.8V ~ 2.43V debido a picos rápidos de corriente de la radio Wi-Fi/BLE (que superan los 500mA), cables USB delgados o un regulador LDO inadecuado. La solución de ingeniería implica agregar condensadores Low-ESR de 10µF a 100µF cerca de VCC y usar reguladores LDO robustos de más de 600mA.",
},
{
pergunta: "¿Cómo solucionar el 'Guru Meditation Error (LoadProhibited)'?",
resposta: "LoadProhibited indica un intento de acceder a un puntero nulo (NULL) o inválido en la memoria. La solución consiste en utilizar Espressif Exception Decoder o addr2line para localizar la línea exacta en el código e implementar comprobaciones defensivas como if (puntero != NULL).",
},
{
pergunta: "¿Por qué se activa el Task Watchdog Timer (TWDT) en FreeRTOS?",
resposta: "El TWDT se activa cuando una tarea de mayor prioridad monopoliza la CPU en un bucle bloqueante (por ejemplo: while(1) sin vTaskDelay), impidiendo que la tarea IDLE alimente el watchdog del sistema operativo.",
},
{
pergunta: "¿Por qué fallan las conexiones HTTPS y TLS con el código -0x2700 en ESP32?",
resposta: "Porque al encenderse, el reloj interno del ESP32 comienza en el año 1970. El validador de certificados TLS considera inválido el certificado del servidor por estar en el 'futuro'. Sincronizar el reloj mediante SNTP (configTime) antes de la conexión resuelve el problema.",
},
];
const faqsFr = [
{
pergunta: "Quelle est la cause de l'erreur 'Brownout detector was triggered' sur l'ESP32 ?",
resposta: "Elle survient lorsque la tension sur la broche 3V3 chute sous 2.8V ~ 2.43V en raison des pics rapides de courant de la radio Wi-Fi/BLE (dépassant 500mA), de câbles USB trop fins ou d'un régulateur LDO sous-dimensionné. La solution d'ingénierie consiste à ajouter des condensateurs Low-ESR de 10µF à 100µF près du VCC et à utiliser un régulateur LDO robuste de 600mA+.",
},
{
pergunta: "Comment résoudre le 'Guru Meditation Error (LoadProhibited)' ?",
resposta: "LoadProhibited indique une tentative d'accès à un pointeur nul (NULL) ou invalide en mémoire. La solution consiste à utiliser l'Espressif Exception Decoder ou addr2line pour identifier la ligne exacte du code et à appliquer des vérifications défensives telles que if (pointeur != NULL).",
},
{
pergunta: "Pourquoi le Task Watchdog Timer (TWDT) se déclenche-t-il sous FreeRTOS ?",
resposta: "Le TWDT se déclenche lorsqu'une tâche de priorité plus élevée monopolise le CPU dans une boucle bloquante (par exemple : while(1) sans vTaskDelay), empêchant la tâche IDLE de nourrir le watchdog du système d'exploitation.",
},
{
pergunta: "Pourquoi les connexions HTTPS et TLS échouent-elles avec l'erreur -0x2700 sur l'ESP32 ?",
resposta: "Au démarrage, l'horloge interne de l'ESP32 démarre à l'année 1970. Le validateur de certificats TLS considère le certificat du serveur invalide car situé dans le 'futur'. Synchroniser l'horloge via SNTP (configTime) avant la connexion résout le problème.",
},
];
const faqsDe = [
{
pergunta: "Was verursacht den Fehler 'Brownout detector was triggered' beim ESP32?",
resposta: "Er tritt auf, wenn die Spannung an der 3V3-Leitung durch schnelle Stromspitzen des Wi-Fi/BLE-Funkmoduls (über 500mA), dünne USB-Kabel oder einen unterdimensionierten LDO-Regler unter 2.8V ~ 2.43V abfällt. Die Lösung besteht darin, Low-ESR-Kondensatoren von 10µF bis 100µF nahe an VCC zu platzieren und robuste LDO-Regler mit 600mA+ einzusetzen.",
},
{
pergunta: "Wie behebt man den 'Guru Meditation Error (LoadProhibited)'?",
resposta: "LoadProhibited weist auf den Versuch hin, auf einen Null-Zeiger (NULL) oder eine ungültige Speicheradresse zuzugreifen. Die Lösung besteht darin, den Espressif Exception Decoder oder addr2line zu verwenden, um die genaue Quellcodezeile zu lokalisieren, und defensive Prüfungen wie if (ptr != NULL) einzufügen.",
},
{
pergunta: "Warum löst der Task Watchdog Timer (TWDT) in FreeRTOS aus?",
resposta: "Der TWDT löst aus, wenn ein Task mit höherer Priorität die CPU in einer blockierenden Schleife monopolisiert (z. B. while(1) ohne vTaskDelay) und so verhindert, dass der IDLE-Task den Watchdog des Betriebssystems bedient.",
},
{
pergunta: "Warum schlagen HTTPS- und TLS-Verbindungen beim ESP32 mit Fehler -0x2700 fehl?",
resposta: "Beim Start beginnt die interne Systemuhr des ESP32 im Jahr 1970. Die TLS-Zertifikatsprüfung stuft das Serverzertifikat als ungültig ein, da es in der fernen 'Zukunft' liegt. Eine Zeitsynchronisation über SNTP (configTime) vor dem Verbindungsaufbau behebt das Problem.",
},
];
const faqsZh = [
{
pergunta: "ESP32 上出现“Brownout detector was triggered”是什么原因?",
resposta: "当 Wi-Fi/BLE 射频产生快速电流峰值(常超过 500mA)时,3V3 电源轨跌到 2.8V ~ 2.43V 以下,就会出现这个错误,通常由过细的 USB 线或容量不足的 LDO 稳压器引起。工程上的解决办法是在 VCC 附近放置 10µF 到 100µF 的低 ESR 旁路电容,并使用 600mA 以上的可靠 LDO 稳压器。",
},
{
pergunta: "如何解决“Guru Meditation Error (LoadProhibited)”?",
resposta: "LoadProhibited 表示试图读取或写入空(NULL)或无效的内存地址。解决办法是用 Espressif Exception Decoder 或 addr2line 定位源代码行,并加入 if (ptr != NULL) 这类防御式检查。",
},
{
pergunta: "为什么 FreeRTOS 中会触发任务看门狗定时器(TWDT)?",
resposta: "当高优先级任务在紧凑的阻塞循环中独占 CPU(例如没有 vTaskDelay 的 while(1)),使负责喂操作系统看门狗的低优先级 IDLE 任务得不到运行时,TWDT 就会触发。",
},
{
pergunta: "为什么 ESP32 上 HTTPS 和 TLS 连接会出现错误 -0x2700?",
resposta: "ESP32 启动时,内部系统时钟从 1970 年纪元开始。TLS 证书校验器会因服务器证书的有效期落在遥远的“未来”而拒绝该证书。在发起 TLS 连接之前,通过 SNTP(configTime)同步时间即可解决。",
},
];
export default async function DiagnosticoLayout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const faqs = isEs ? faqsEs : isEn ? faqsEn : isFr ? faqsFr : isZh ? faqsZh : isDe ? faqsDe : faqsPt;
const canonPath = isEs ? "/es/diagnostico" : isEn ? "/en/diagnostics" : isFr ? "/fr/diagnostic" : isZh ? "/zh-CN/diagnostics" : isDe ? "/de/diagnose" : "/diagnostico";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEs ? "Inicio" : isEn ? "Home" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: isEs ? "Diagnóstico y errores comunes" : isEn ? "Diagnostics & Common Errors" : isFr ? "Diagnostic et erreurs courantes" : isZh ? "诊断与常见错误" : isDe ? "Diagnose und häufige Fehler" : "Diagnóstico & Erros Comuns", caminho: canonPath },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.perguntas(faqs)
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isEs ? "Guía de diagnóstico y errores en ESP32" : isEn ? "ESP32 Error Diagnostics & Debugging Guide" : isFr ? "Guide de diagnostic et erreurs sur ESP32" : isZh ? "ESP32 故障诊断指南" : isDe ? "ESP32-Fehlerdiagnose und Debugging-Leitfaden" : "Guia de Diagnóstico e Erros no ESP32",
descricao: isEs
? "Herramienta y guía técnica de análisis de fallas, pánicos de CPU y decodificación de registros en ESP32."
: isEn
? "Technical guide and log decoder for troubleshooting CPU panics, crashes, and exceptions on ESP32."
: isFr
? "Outil et guide technique d'analyse des pannes, des paniques CPU et du décodage de logs sur ESP32."
: isZh ? "用于分析故障、CPU 异常和解码 ESP32 日志的工具与技术指南。" : isDe
? "Werkzeug und technischer Leitfaden zur Fehleranalyse, Behebung von CPU-Panics und Dekodierung von Logs auf dem ESP32."
: "Ferramenta e guia técnico de análise de falhas, pânicos de CPU e decodificação de logs no ESP32.",
caminho: canonPath,
locale,
})
),
}}
/>
{children}
</>
);
}
+730
View File
@@ -0,0 +1,730 @@
"use client";
import { useState, useMemo, useRef } from "react";
import { usePathname } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import * as diagnosticoPt from "@/lib/diagnosticoData";
import * as diagnosticoEn from "@/lib/data/en/diagnostico";
import * as diagnosticoEs from "@/lib/data/es/diagnostico";
import * as diagnosticoFr from "@/lib/data/fr/diagnostico";
import * as diagnosticoDe from "@/lib/data/de/diagnostico";
import * as diagnosticoZh from "@/lib/data/zh-CN/diagnostico";
import {
Activity,
AlertTriangle,
Check,
CheckCircle2,
ChevronDown,
Copy,
Cpu,
ExternalLink,
HelpCircle,
Layers,
LayoutGrid,
RotateCcw,
Search,
ShieldAlert,
Terminal,
Wifi,
Wrench,
X,
XCircle,
Zap,
} from "lucide-react";
/** Os rótulos dos sintomas vêm com emoji nos dados; a interface usa só texto e ícones. */
const semEmoji = (texto) => texto.replace(/^[\p{Extended_Pictographic}\uFE0F\s]+/u, "");
const ICONES = { Zap, Cpu, Layers, Activity, Terminal, Wifi };
const EXEMPLOS_LOG_PT = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const EXEMPLOS_LOG_EN = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["TLS Handshake", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const EXEMPLOS_LOG_ES = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const EXEMPLOS_LOG_FR = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const EXEMPLOS_LOG_DE = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["TLS-Handshake", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const EXEMPLOS_LOG_ZH = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["任务看门狗", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["TLS 握手", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const GRAVIDADE = {
"Crítica": "text-danger",
"Critical": "text-danger",
"Critique": "text-danger",
"Kritisch": "text-danger",
Alta: "text-gold",
High: "text-gold",
"Élevée": "text-gold",
Hoch: "text-gold",
"Média": "text-accent",
Medium: "text-accent",
Media: "text-accent",
Moyenne: "text-accent",
Mittel: "text-accent",
"严重": "text-danger",
"高": "text-gold",
"中": "text-accent",
};
const CHECKLISTS_PT = [
{
icon: Zap,
titulo: "Hardware e alimentação",
itens: [
"Capacitor de 10 µF a 100 µF de baixo ESR no VCC, mais um cerâmico de 100 nF junto ao chip.",
"LDO dimensionado para picos de 600 mA a 1 A, com folga térmica.",
"Nenhum periférico forçando nível lógico nos pinos de strapping durante o boot.",
"Capacitor de 10 µF ou 1 µF no pino EN (RST) para auto-reset estável na gravação.",
],
},
{
icon: Layers,
titulo: "Firmware e FreeRTOS",
itens: [
"Toda tarefa FreeRTOS cede a CPU com vTaskDelay, filas ou semáforos.",
"Toda ISR marcada com IRAM_ATTR e sem chamadas bloqueantes.",
"Sem uso contínuo de String do Arduino em laços, para evitar fragmentação do heap.",
"Horário sincronizado por SNTP antes de abrir conexões TLS/HTTPS.",
],
},
];
const CHECKLISTS_EN = [
{
icon: Zap,
titulo: "Hardware and Power Supply",
itens: [
"10 µF to 100 µF low-ESR capacitor on VCC, plus a 100 nF ceramic capacitor close to the chip.",
"LDO regulator sized for 600 mA to 1 A current spikes, with adequate thermal margin.",
"No external peripherals forcing logic levels on strapping pins during reset and boot.",
"10 µF or 1 µF capacitor on the EN (RST) pin for stable auto-reset flashing.",
],
},
{
icon: Layers,
titulo: "Firmware and FreeRTOS",
itens: [
"Every FreeRTOS task yields CPU time with vTaskDelay, queues, or semaphores.",
"Every ISR marked with IRAM_ATTR with zero blocking calls.",
"Avoid continuous heap reallocations using Arduino Strings in tight loops.",
"Clock synchronized via SNTP before attempting TLS/HTTPS handshakes.",
],
},
];
const CHECKLISTS_ES = [
{
icon: Zap,
titulo: "Hardware y alimentación",
itens: [
"Condensador de 10 µF a 100 µF de bajo ESR en VCC, más uno cerámico de 100 nF junto al chip.",
"Regulador LDO dimensionado para picos de 600 mA a 1 A, con margen térmico.",
"Ningún periférico forzando niveles lógicos en los pines de strapping durante el arranque.",
"Condensador de 10 µF o 1 µF en el pin EN (RST) para auto-reset estable durante la programación.",
],
},
{
icon: Layers,
titulo: "Firmware y FreeRTOS",
itens: [
"Cada tarea de FreeRTOS cede la CPU con vTaskDelay, colas o semáforos.",
"Cada ISR marcada con IRAM_ATTR y sin llamadas bloqueantes.",
"Sin uso continuo de String de Arduino en bucles para evitar la fragmentación del heap.",
"Hora sincronizada mediante SNTP antes de abrir conexiones TLS/HTTPS.",
],
},
];
const CHECKLISTS_FR = [
{
icon: Zap,
titulo: "Matériel et alimentation",
itens: [
"Condensateur de 10 µF à 100 µF à faible ESR sur VCC, plus un céramique de 100 nF près de la puce.",
"Régulateur LDO dimensionné pour des pointes de 600 mA à 1 A, avec marge thermique.",
"Aucun périphérique ne forçant de niveau logique sur les broches de strapping pendant le boot.",
"Condensateur de 10 µF ou 1 µF sur la broche EN (RST) pour un auto-reset stable au flashage.",
],
},
{
icon: Layers,
titulo: "Firmware et FreeRTOS",
itens: [
"Chaque tâche FreeRTOS cède la CPU avec vTaskDelay, des files ou des sémaphores.",
"Chaque ISR marquée avec IRAM_ATTR et exempte d'appels bloquants.",
"Pas d'usage continu de String d'Arduino dans les boucles, afin d'éviter la fragmentation du tas.",
"Horloge synchronisée par SNTP avant d'ouvrir des connexions TLS/HTTPS.",
],
},
];
const CHECKLISTS_DE = [
{
icon: Zap,
titulo: "Hardware und Spannungsversorgung",
itens: [
"10 µF bis 100 µF Low-ESR-Kondensator an VCC, plus ein 100-nF-Keramikkondensator nah am Chip.",
"LDO-Regler ausgelegt für 600 mA bis 1 A Stromspitzen mit thermischer Reserve.",
"Keine Peripheriegeräte, die beim Booten Logikpegel an Strapping-Pins erzwingen.",
"10 µF- oder 1 µF-Kondensator am EN-Pin (RST) für zuverlässigen Auto-Reset beim Flashen.",
],
},
{
icon: Layers,
titulo: "Firmware und FreeRTOS",
itens: [
"Jeder FreeRTOS-Task gibt CPU-Zeit mit vTaskDelay, Queues oder Semaphoren ab.",
"Jede ISR mit IRAM_ATTR versehen und frei von blockierenden Aufrufen.",
"Keine fortlaufende Verwendung von Arduino-Strings in Schleifen zur Vermeidung von Heap-Fragmentierung.",
"Uhrzeit vor dem Aufbau von TLS/HTTPS-Verbindungen per SNTP synchronisiert.",
],
},
];
const CHECKLISTS_ZH = [
{
icon: Zap,
titulo: "硬件与供电",
itens: [
"VCC 上接 10 µF 到 100 µF 的低 ESR 电容,并在靠近芯片处再加一个 100 nF 陶瓷电容。",
"LDO 稳压器按 600 mA 到 1 A 的电流峰值选型,并留有足够的散热余量。",
"复位和启动期间,没有外部外设在启动配置引脚上强制逻辑电平。",
"EN(RST)引脚上接 10 µF 或 1 µF 电容,使自动复位烧录更稳定。",
],
},
{
icon: Layers,
titulo: "固件与 FreeRTOS",
itens: [
"每个 FreeRTOS 任务都通过 vTaskDelay、队列或信号量让出 CPU 时间。",
"每个 ISR 都标记了 IRAM_ATTR,且不包含任何阻塞调用。",
"避免在紧凑循环中使用 Arduino String 造成持续的堆重新分配。",
"在尝试 TLS/HTTPS 握手之前,先通过 SNTP 同步时钟。",
],
},
];
export default function DiagnosticoPage() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const { categoriasDiagnostico, sintomasRapidos, errosCatalogo, regrasDecodificadorLog } = isEs ? diagnosticoEs : isEn ? diagnosticoEn : isFr ? diagnosticoFr : isZh ? diagnosticoZh : isDe ? diagnosticoDe : diagnosticoPt;
const exemplosLog = isEs ? EXEMPLOS_LOG_ES : isEn ? EXEMPLOS_LOG_EN : isFr ? EXEMPLOS_LOG_FR : isZh ? EXEMPLOS_LOG_ZH : isDe ? EXEMPLOS_LOG_DE : EXEMPLOS_LOG_PT;
const checklists = isEs ? CHECKLISTS_ES : isEn ? CHECKLISTS_EN : isFr ? CHECKLISTS_FR : isZh ? CHECKLISTS_ZH : isDe ? CHECKLISTS_DE : CHECKLISTS_PT;
const [termoBusca, setTermoBusca] = useState("");
const [categoriaAtiva, setCategoriaAtiva] = useState("todos");
const [sintomaAtivo, setSintomaAtivo] = useState(null);
const [cardAberto, setCardAberto] = useState(null);
const [linguagemCodigo, setLinguagemCodigo] = useState({}); // { [id]: 'arduino' | 'espidf' }
const [copiadoId, setCopiadoId] = useState(null);
const searchInputRef = useRef(null);
// Estado do Analisador de Logs
const [logInput, setLogInput] = useState("");
const [resultadoLog, setResultadoLog] = useState(null);
// Função de Análise do Log
const analisarLog = (texto) => {
setLogInput(texto);
if (!texto || texto.trim() === "") {
setResultadoLog(null);
return;
}
for (const regra of regrasDecodificadorLog) {
if (regra.padrao.test(texto)) {
setResultadoLog(regra);
return;
}
}
setResultadoLog(
isEs
? {
titulo: "Patrón de error no categorizado automáticamente",
tipo: "Desconocido",
explicacao:
"No identificamos una firma clásica de Guru Meditation o Brownout en este fragmento. Verifique que la velocidad de baudios (ej: 115200) sea correcta y si el encabezado 'rst:' o 'panic' está presente.",
acaoRecomendada:
"Busque palabras clave como 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' o 'panic' en la consola serie.",
}
: isEn
? {
titulo: "Error pattern not automatically classified",
tipo: "Unknown",
explicacao:
"We could not identify a classic Guru Meditation or Brownout signature in this snippet. Verify that the baud rate (e.g. 115200) is correct and whether the 'rst:' or 'panic' header is present.",
acaoRecomendada:
"Look for keywords such as 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog', or 'panic' in the serial output.",
}
: isFr
? {
titulo: "Modèle d'erreur non catégorisé automatiquement",
tipo: "Inconnu",
explicacao:
"Nous n'avons pas identifié de signature classique de Guru Meditation ou Brownout dans cet extrait. Vérifiez que la vitesse en bauds (ex. : 115200) est correcte et si l'en-tête 'rst:' ou 'panic' est présent.",
acaoRecomendada:
"Recherchez des mots-clés tels que 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' ou 'panic' dans la console série.",
}
: isZh ? {
titulo: "未能自动归类的错误模式",
tipo: "未知",
explicacao: "在这段内容中没有识别出典型的 Guru Meditation 或 Brownout 特征。请检查波特率(例如 115200)是否正确,以及是否包含以 'rst:' 或 'panic' 开头的信息。",
acaoRecomendada: "在串口控制台中查找 'Guru Meditation'、'rst:'、'LoadProhibited'、'watchdog' 或 'panic' 等关键字。",
} : isDe
? {
titulo: "Fehlermuster nicht automatisch kategorisiert",
tipo: "Unbekannt",
explicacao:
"Wir konnten in diesem Ausschnitt keine klassische Guru-Meditation- oder Brownout-Signatur erkennen. Prüfen Sie, ob die Baudrate (z. B. 115200) korrekt ist und ob der Header 'rst:' oder 'panic' vorhanden ist.",
acaoRecomendada:
"Suchen Sie in der seriellen Konsole nach Begriffen wie 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' oder 'panic'.",
}
: {
titulo: "Padrão de erro não categorizado automaticamente",
tipo: "Desconhecido",
explicacao:
"Não identificamos uma assinatura clássica de Guru Meditation ou Brownout neste trecho. Verifique se a taxa de baud rate (ex: 115200) está correta e se o cabeçalho 'rst:' ou 'panic' está presente.",
acaoRecomendada:
"Procure por palavras-chave como 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' ou 'panic' no console serial.",
}
);
};
const copiarParaClipboard = (texto, id) => {
navigator.clipboard.writeText(texto);
setCopiadoId(id);
setTimeout(() => setCopiadoId(null), 2000);
};
// Filtragem dos erros
const errosFiltrados = useMemo(() => {
const termo = termoBusca.toLowerCase().trim();
return errosCatalogo.filter((erro) => {
const matchCategoria =
categoriaAtiva === "todos" || erro.categoria === categoriaAtiva;
const matchSintoma =
!sintomaAtivo || erro.sintomas.includes(sintomaAtivo);
const matchBusca =
!termo ||
erro.titulo.toLowerCase().includes(termo) ||
erro.resumo.toLowerCase().includes(termo) ||
erro.causaRaiz.toLowerCase().includes(termo) ||
erro.logSerial.toLowerCase().includes(termo);
return matchCategoria && matchSintoma && matchBusca;
});
}, [categoriaAtiva, sintomaAtivo, termoBusca, errosCatalogo]);
const temFiltroAtivo =
termoBusca.trim() !== "" ||
categoriaAtiva !== "todos" ||
sintomaAtivo !== null;
const limparTodosFiltros = () => {
setTermoBusca("");
setCategoriaAtiva("todos");
setSintomaAtivo(null);
searchInputRef.current?.focus();
};
const toggleCard = (id) => {
setCardAberto((prev) => (prev === id ? null : id));
};
const setLang = (id, lang) => {
setLinguagemCodigo((prev) => ({ ...prev, [id]: lang }));
};
const totalFiltros = (termoBusca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (sintomaAtivo ? 1 : 0);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Diagnóstico" : isEn ? "Diagnostics" : isFr ? "Diagnostic" : isZh ? "诊断" : isDe ? "Diagnose" : "Diagnóstico" }]}
icon={AlertTriangle}
label={isEs ? "Depuración de firmware" : isEn ? "Firmware Debugging" : isFr ? "Débogage du firmware" : isZh ? "固件调试" : isDe ? "Firmware-Debugging" : "Depuração de firmware"}
title={isEs ? "Diagnóstico de fallas del ESP32" : isEn ? "ESP32 Diagnostics and Crash Decoder" : isFr ? "Diagnostic des pannes de l'ESP32" : isZh ? "ESP32 故障诊断" : isDe ? "ESP32-Fehlerdiagnose und Crash-Decoder" : "Diagnóstico de falhas do ESP32"}
lede={
isEs
? "Comprenda la causa raíz de las fallas por Brownout, Guru Meditation, Watchdog y Stack Overflow, y aplique la corrección de ingeniería en lugar de soluciones improvisadas."
: isEn
? "Understand the root cause of Brownout, Guru Meditation, Watchdog, and Stack Overflow crashes, and apply engineering solutions instead of workarounds."
: isFr
? "Comprenez la cause racine des pannes de Brownout, Guru Meditation, Watchdog et Stack Overflow, et appliquez la correction d'ingénierie plutôt qu'un bricolage."
: isZh ? "弄清 Brownout、Guru Meditation、Watchdog 和栈溢出的成因,并采用工程上的正确修复,而不是临时补救。" : isDe
? "Verstehen Sie die Ursache von Brownout, Guru Meditation, Watchdog und Stack Overflow und wenden Sie saubere Ingenieurlösungen statt Notbehelfen an."
: "Entenda a causa de Brownout, Guru Meditation, Watchdog e Stack Overflow, e aplique a correção de engenharia, não o remendo."
}
>
<a
href="https://cienciaembarcada.com.br/publicacoes/esp32-5-erros-comuns-e-como-resolve-los-profissionalmente/"
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong"
>
{isEs ? "Basado en el artículo de Ciência Embarcada" : isEn ? "Based on article by Ciência Embarcada" : isFr ? "D'après l'article de Ciência Embarcada" : isZh ? "基于 Ciência Embarcada 的文章" : isDe ? "Basierend auf dem Artikel von Ciência Embarcada" : "Baseado no artigo do Ciência Embarcada"}
<ExternalLink className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> {isEs ? "(abre en una nueva pestaña)" : isEn ? "(opens in a new tab)" : isFr ? "(ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? "(öffnet in neuem Tab)" : "(abre em nova aba)"}</span>
</a>
</PageHero>
<section className="shell pt-10 sm:pt-12" aria-labelledby="decodificador-titulo">
<div className="panel p-5 sm:p-8">
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-end">
<div className="max-w-xl">
<h2 id="decodificador-titulo" className="section-title">
{isEs ? "Pegue el registro y descubra la causa" : isEn ? "Paste the log to see the cause" : isFr ? "Collez le journal et découvrez la cause" : isZh ? "粘贴日志,查看原因" : isDe ? "Log einfügen und Ursache ermitteln" : "Cole o log e veja a causa"}
</h2>
<p className="mt-2 text-sm text-muted">
{isEs ? "Copie el fragmento del monitor serie. El diagnóstico aparece al instante." : isEn ? "Copy the serial monitor output snippet. Diagnostics appear instantly." : isFr ? "Copiez l'extrait du moniteur série. Le diagnostic apparaît immédiatement." : isZh ? "复制串口监视器中的内容,诊断结果立即显示。" : isDe ? "Kopieren Sie den Ausschnitt aus dem seriellen Monitor. Die Diagnose erscheint sofort." : "Copie o trecho do monitor serial. O diagnóstico aparece na hora."}
</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<span className="text-sm text-muted">{isEs ? "Probar con" : isEn ? "Test with" : isFr ? "Tester avec" : isZh ? "试试这些" : isDe ? "Testen mit" : "Testar com"}</span>
{exemplosLog.map(([rotulo, texto]) => (
<button key={rotulo} type="button" onClick={() => analisarLog(texto)} className="chip-btn">
{rotulo}
</button>
))}
</div>
</div>
<div className="relative mt-5">
<label htmlFor="log-serial" className="sr-only">
{isEs ? "Registro del monitor serie" : isEn ? "Serial monitor log" : isFr ? "Journal du moniteur série" : isZh ? "串口监视器日志" : isDe ? "Serieller Monitor-Log" : "Log do monitor serial"}
</label>
<textarea
id="log-serial"
rows={4}
value={logInput}
onChange={(e) => analisarLog(e.target.value)}
placeholder={isEs ? "Pegue el registro del monitor serie aquí" : isEn ? "Paste serial monitor log here" : isFr ? "Collez le journal du moniteur série ici" : isZh ? "在此粘贴串口监视器日志" : isDe ? "Seriellen Monitor-Log hier einfügen" : "Cole o log do monitor serial aqui"}
spellCheck={false}
className="code-panel field !min-h-32 w-full resize-y !rounded-xl !border-white/10 !bg-[var(--code-bg)] p-4 font-mono text-sm !text-[#e9eef4] placeholder:!text-[#a6afbd]"
/>
{logInput && (
<button type="button" onClick={() => analisarLog("")} className="absolute right-3 top-3 inline-flex min-h-11 items-center gap-1 rounded-full border border-white/15 px-3 text-xs font-medium text-[#e9eef4] hover:bg-white/10">
<X className="h-3.5 w-3.5" aria-hidden="true" />
{isEs ? "Limpiar" : isEn ? "Clear" : isFr ? "Effacer" : isZh ? "清除" : isDe ? "Löschen" : "Limpar"}
</button>
)}
</div>
<div role="status" aria-live="polite">
{resultadoLog && (
<div className="callout callout-warn mt-4 flex items-start gap-3">
<ShieldAlert className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
<div className="min-w-0 space-y-2">
<div className="flex flex-wrap items-center gap-2">
<h3 className="font-semibold text-ink">{resultadoLog.titulo}</h3>
<span className="chip">{resultadoLog.tipo}</span>
</div>
<p><strong className="font-semibold text-ink">{isEs ? "Causa probable:" : isEn ? "Likely cause:" : isFr ? "Cause probable :" : isZh ? "可能的原因:" : isDe ? "Wahrscheinliche Ursache :" : "Causa provável:"}</strong> {resultadoLog.explicacao}</p>
<p><strong className="font-semibold text-ink">{isEs ? "Qué hacer:" : isEn ? "What to do:" : isFr ? "Que faire :" : isZh ? "该怎么做:" : isDe ? "Was zu tun ist :" : "O que fazer:"}</strong> {resultadoLog.acaoRecomendada}</p>
</div>
</div>
)}
</div>
</div>
</section>
<section className="shell section pt-12 sm:pt-14" aria-labelledby="catalogo-titulo">
<h2 id="catalogo-titulo" className="section-title">
{isEs ? "Catálogo de fallas" : isEn ? "Fault catalog" : isFr ? "Catalogue de pannes" : isZh ? "故障目录" : isDe ? "Fehlerkatalog" : "Catálogo de falhas"}
</h2>
<div className="panel mt-6 p-5 sm:p-6">
<div className="relative">
<label htmlFor="busca-erro" className="sr-only">
{isEs ? "Buscar por error, síntoma o mensaje serie" : isEn ? "Search by error, symptom, or serial message" : isFr ? "Rechercher par erreur, symptôme ou message série" : isZh ? "按错误、症状或串口信息搜索" : isDe ? "Nach Fehler, Symptom oder serieller Meldung suchen" : "Buscar por erro, sintoma ou mensagem serial"}
</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-erro"
ref={searchInputRef}
type="search"
value={termoBusca}
onChange={(e) => setTermoBusca(e.target.value)}
placeholder={isEs ? "Buscar error, síntoma o mensaje" : isEn ? "Search error, symptom, or message" : isFr ? "Rechercher une erreur, un symptôme ou un message" : isZh ? "搜索错误、症状或信息" : isDe ? "Fehler, Symptom oder Meldung suchen" : "Buscar erro, sintoma ou mensagem"}
autoComplete="off"
className="field pl-12 pr-4 text-base"
/>
</div>
<div className="mt-5">
<h3 className="text-sm font-semibold text-ink">{isEs ? "Síntoma" : isEn ? "Symptom" : isFr ? "Symptôme" : isZh ? "症状" : isDe ? "Symptom" : "Sintoma"}</h3>
<div className="mt-3 flex flex-wrap gap-2">
{sintomasRapidos.map((sintoma) => (
<button key={sintoma.id} type="button" onClick={() => setSintomaAtivo(sintomaAtivo === sintoma.id ? null : sintoma.id)} aria-pressed={sintomaAtivo === sintoma.id} className="chip-btn">
{semEmoji(sintoma.rotulo)}
</button>
))}
</div>
</div>
<div className="mt-5 border-t border-line pt-5">
<h3 className="text-sm font-semibold text-ink">{isEs ? "Área" : isEn ? "Area" : isFr ? "Domaine" : isZh ? "领域" : isDe ? "Bereich" : "Área"}</h3>
<div className="mt-3 flex flex-wrap gap-2">
<button type="button" onClick={() => setCategoriaAtiva("todos")} aria-pressed={categoriaAtiva === "todos"} className="chip-btn">
<LayoutGrid className="h-4 w-4" aria-hidden="true" />
{isEs ? "Todas" : isEn ? "All" : isFr ? "Tous" : isZh ? "全部" : isDe ? "Alle" : "Todas"}
<span className="tabular-nums opacity-80">{errosCatalogo.length}</span>
</button>
{categoriasDiagnostico.map((cat) => {
const Icone = ICONES[cat.icone] ?? AlertTriangle;
const total = errosCatalogo.filter((e) => e.categoria === cat.id).length;
return (
<button key={cat.id} type="button" onClick={() => setCategoriaAtiva(cat.id)} aria-pressed={categoriaAtiva === cat.id} className="chip-btn">
<Icone className="h-4 w-4" aria-hidden="true" />
{cat.nome.split(/ &|,/)[0]}
<span className="tabular-nums opacity-80">{total}</span>
</button>
);
})}
</div>
</div>
</div>
<div className="mt-6 flex flex-wrap items-center justify-between gap-3">
<p role="status" aria-live="polite" className="text-sm font-semibold text-ink">
{errosFiltrados.length} {errosFiltrados.length === 1 ? (isEs ? "falla" : isEn ? "fault" : isFr ? "panne" : isZh ? "个故障" : isDe ? "Fehler" : "falha") : (isEs ? "fallas" : isEn ? "faults" : isFr ? "pannes" : isZh ? "个故障" : isDe ? "Fehler" : "falhas")}
{totalFiltros > 0 && <span className="font-normal text-muted">{isEs ? " con los filtros actuales" : isEn ? " with current filters" : isFr ? " avec les filtres actuels" : isZh ? "(当前筛选下)" : isDe ? " mit aktuellen Filtern" : " com os filtros atuais"}</span>}
</p>
{temFiltroAtivo && (
<button type="button" onClick={limparTodosFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
{isEs ? "Restablecer filtros" : isEn ? "Reset filters" : isFr ? "Réinitialiser les filtres" : isZh ? "重置筛选" : isDe ? "Filter zurücksetzen" : "Redefinir filtros"}
</button>
)}
</div>
<div className="mt-3 space-y-3">
{errosFiltrados.length === 0 ? (
<div className="card px-6 py-14 text-center">
<HelpCircle className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">
{isEs ? "Ninguna falla coincide con estos filtros" : isEn ? "No faults matching these filters" : isFr ? "Aucune panne ne correspond à ces filtres" : isZh ? "没有符合这些筛选条件的故障" : isDe ? "Keine Fehler entsprechen diesen Filtern" : "Nenhuma falha com esses filtros"}
</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
{isEs ? "Busque por un término más general o elimine el síntoma y el área seleccionados." : isEn ? "Search for a more general term or remove selected symptom and area." : isFr ? "Recherchez un terme plus général ou retirez le symptôme et le domaine sélectionnés." : isZh ? "请搜索更通用的词,或去掉已选的症状和领域。" : isDe ? "Suchen Sie nach einem allgemeineren Begriff oder entfernen Sie gewähltes Symptom und Bereich." : "Busque por um termo mais geral ou remova o sintoma e a área selecionados."}
</p>
<button type="button" onClick={limparTodosFiltros} className="btn btn-primary mt-6">
{isEs ? "Limpiar filtros" : isEn ? "Clear filters" : isFr ? "Effacer les filtres" : isZh ? "清除筛选" : isDe ? "Filter zurücksetzen" : "Limpar filtros"}
</button>
</div>
) : (
errosFiltrados.map((erro) => {
const estaAberto = cardAberto === erro.id;
const lang = linguagemCodigo[erro.id] || "arduino";
const codigoAtual =
lang === "arduino" ? erro.codigoArduino : lang === "espidf" ? erro.codigoEspIdf : erro.codigoMicroPython || (isEs ? "# Ejemplo no aplicable" : isEn ? "# Example not applicable" : isFr ? "# Exemple non applicable" : isZh ? "# 示例不适用" : isDe ? "# Beispiel nicht anwendbar" : "# Exemplo não aplicável");
const catInfo = categoriasDiagnostico.find((c) => c.id === erro.categoria);
const IconeCat = ICONES[catInfo?.icone] ?? AlertTriangle;
return (
<article key={erro.id} id={erro.id} className={`card scroll-mt-28 overflow-hidden ${estaAberto ? "border-line-strong" : ""}`}>
<h3>
<button
type="button"
onClick={() => toggleCard(erro.id)}
aria-expanded={estaAberto}
aria-controls={`detalhe-${erro.id}`}
className="flex w-full cursor-pointer items-start justify-between gap-4 p-5 text-left sm:p-6"
>
<span className="min-w-0">
<span className="flex flex-wrap items-center gap-2">
<span className="chip">
<IconeCat className="h-3.5 w-3.5 text-accent" aria-hidden="true" />
{catInfo?.nome}
</span>
<span className={`chip ${GRAVIDADE[erro.gravidade] ?? "text-accent"}`}>
{isEs ? (
<>Severidad {erro.gravidade.toLowerCase()}</>
) : isEn ? (
<>Severity: {erro.gravidade.toLowerCase()}</>
) : isFr ? (
<>Gravité : {erro.gravidade.toLowerCase()}</>
) : isZh ? ( <>严重程度:{erro.gravidade}</> ) : isDe ? (
<>Schweregrad: {erro.gravidade.toLowerCase()}</>
) : (
<>Gravidade {erro.gravidade.toLowerCase()}</>
)}
</span>
</span>
<span className="mt-3 block font-display text-xl font-semibold tracking-[-0.03em] text-ink">{erro.titulo}</span>
<span className="mt-1.5 block text-sm font-normal leading-relaxed text-muted">{erro.resumo}</span>
</span>
<span className="mt-1 grid h-9 w-9 shrink-0 place-items-center rounded-full bg-surface-2 text-muted">
<ChevronDown className={`h-4 w-4 transition-transform ${estaAberto ? "rotate-180" : ""}`} aria-hidden="true" />
</span>
</button>
</h3>
{estaAberto && (
<div id={`detalhe-${erro.id}`} className="space-y-6 border-t border-line p-5 sm:p-6">
<div>
<div className="flex items-center justify-between gap-3">
<h4 className="flex items-center gap-2 text-sm font-semibold text-ink">
<Terminal className="h-4 w-4 text-accent" aria-hidden="true" />
{isEs ? "Cómo aparece en el monitor serie" : isEn ? "How it appears in serial monitor" : isFr ? "Apparence dans le moniteur série" : isZh ? "在串口监视器中的样子" : isDe ? "Erscheinungsbild im seriellen Monitor" : "Como aparece no monitor serial"}
</h4>
<button type="button" onClick={() => copiarParaClipboard(erro.logSerial, `log-${erro.id}`)} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
{copiadoId === `log-${erro.id}` ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `log-${erro.id}` ? (isEs ? "Copiado" : isEn ? "Copied" : isFr ? "Copié" : isZh ? "已复制" : isDe ? "Kopiert" : "Copiado") : (isEs ? "Copiar registro" : isEn ? "Copy log" : isFr ? "Copier le log" : isZh ? "复制日志" : isDe ? "Log kopieren" : "Copiar log")}
</button>
</div>
<div className="code-panel mt-1">
<pre tabIndex={0}><code className="text-[#e9eef4]">{erro.logSerial}</code></pre>
</div>
</div>
<div>
<h4 className="flex items-center gap-2 text-sm font-semibold text-ink">
<Cpu className="h-4 w-4 text-accent" aria-hidden="true" />
{isEs ? "Causa raíz" : isEn ? "Root cause" : isFr ? "Cause racine" : isZh ? "根本原因" : isDe ? "Ursache" : "Causa raiz"}
</h4>
<p className="callout mt-2">{erro.causaRaiz}</p>
</div>
<div className="grid gap-4 md:grid-cols-2">
<div className="callout callout-danger">
<p className="flex items-center gap-2 font-semibold text-ink">
<XCircle className="h-4 w-4 shrink-0 text-danger" aria-hidden="true" />
{isEs ? "La solución improvisada común" : isEn ? "The common workaround" : isFr ? "Le bricolage courant" : isZh ? "常见的临时补救" : isDe ? "Der verbreitete Notbehelf" : "O remendo comum"}
</p>
<p className="mt-2 font-medium text-ink">{erro.gambiarra.titulo}</p>
<p className="mt-1">{erro.gambiarra.descricao}</p>
<p className="mt-2"><strong className="font-semibold text-danger">{isEs ? "Consecuencia:" : isEn ? "Consequence:" : isFr ? "Conséquence :" : isZh ? "后果:" : isDe ? "Folge :" : "Consequência:"}</strong> {erro.gambiarra.consequencia}</p>
</div>
<div className="callout callout-ok">
<p className="flex items-center gap-2 font-semibold text-ink">
<CheckCircle2 className="h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
{isEs ? "La solución de ingeniería" : isEn ? "The engineering solution" : isFr ? "La solution d'ingénierie" : isZh ? "工程上的解决方案" : isDe ? "Die Ingenieurlösung" : "A solução de engenharia"}
</p>
<p className="mt-2 font-medium text-ink">{erro.solucaoEngenharia.titulo}</p>
<ul className="mt-2 space-y-1.5">
{erro.solucaoEngenharia.passos.map((passo) => (
<li key={passo} className="flex items-start gap-2">
<Check className="mt-1 h-3.5 w-3.5 shrink-0 text-ok" aria-hidden="true" />
{passo}
</li>
))}
</ul>
</div>
</div>
<div>
<div className="flex flex-wrap items-center justify-between gap-3">
<div role="group" aria-label={isEs ? "Lenguaje del ejemplo" : isEn ? "Example language" : isFr ? "Langage de l'exemple" : isZh ? "示例语言" : isDe ? "Sprache des Beispiels" : "Linguagem do exemplo"} className="flex flex-wrap gap-2">
{[
["arduino", "Arduino C++"],
["espidf", "ESP-IDF (C)"],
["micropython", "MicroPython"],
].map(([id, rotulo]) => (
<button key={id} type="button" onClick={() => setLang(erro.id, id)} aria-pressed={lang === id} className="chip-btn">
{rotulo}
</button>
))}
</div>
<button type="button" onClick={() => copiarParaClipboard(codigoAtual, `code-${erro.id}`)} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
{copiadoId === `code-${erro.id}` ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `code-${erro.id}` ? (isEs ? "Copiado" : isEn ? "Copied" : isFr ? "Copié" : isZh ? "已复制" : isDe ? "Kopiert" : "Copiado") : (isEs ? "Copiar código" : isEn ? "Copy code" : isFr ? "Copier le code" : isZh ? "复制代码" : isDe ? "Code kopieren" : "Copiar código")}
</button>
</div>
<div className="code-panel mt-3">
<pre tabIndex={0}><code className="text-[#e9eef4]">{codigoAtual}</code></pre>
</div>
</div>
<div className="callout callout-warn flex items-start gap-3">
<Wrench className="mt-0.5 h-4 w-4 shrink-0 text-gold" aria-hidden="true" />
<p><strong className="font-semibold text-ink">{isEs ? "Consejo de ingeniería:" : isEn ? "Engineering tip:" : isFr ? "Conseil d'ingénierie :" : isZh ? "工程提示:" : isDe ? "Praxistipp :" : "Dica de engenharia:"}</strong> {erro.dicaPro}</p>
</div>
</div>
)}
</article>
);
})
)}
</div>
</section>
<section className="shell pb-20 md:pb-28" aria-labelledby="checklist-titulo">
<h2 id="checklist-titulo" className="section-title">
{isEs ? "Lista de verificación previa a campo" : isEn ? "Pre-deployment checklist" : isFr ? "Checklist avant déploiement" : isZh ? "上线前的检查清单" : isDe ? "Checkliste vor dem Feldeinsatz" : "Checklist antes de ir para campo"}
</h2>
<p className="mt-3 max-w-2xl text-base text-muted">
{isEs ? "Elementos esenciales para validar en hardware y firmware antes de entregar el producto." : isEn ? "Essential items to validate on hardware and firmware before shipping a product." : isFr ? "Éléments essentiels à valider sur le matériel et le firmware avant de livrer le produit." : isZh ? "在交付产品之前,需要在硬件和固件上验证的关键项目。" : isDe ? "Wesentliche Punkte zur Prüfung von Hardware und Firmware vor der Auslieferung." : "Itens essenciais para validar no hardware e no firmware antes de entregar o produto."}
</p>
<div className="mt-8 grid gap-4 md:grid-cols-2">
{checklists.map(({ icon: Icon, titulo, itens }) => (
<div key={titulo} className="card p-5 sm:p-7">
<h3 className="flex items-center gap-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
<span className="grid h-9 w-9 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-4 w-4" aria-hidden="true" />
</span>
{titulo}
</h3>
<ul className="mt-5 space-y-3">
{itens.map((item) => (
<li key={item} className="flex items-start gap-3 text-sm leading-relaxed text-ink-soft">
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
{item}
</li>
))}
</ul>
</div>
))}
</div>
</section>
</main>
<Footer />
</div>
);
}
+277
View File
@@ -0,0 +1,277 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import { notFound } from "next/navigation";
import CodeExample from "@/components/CodeExample";
import frameworksDataPt from "@/public/frameworks.json";
import frameworksDataEn from "@/data/en/frameworks.json";
import frameworksDataEs from "@/data/es/frameworks.json";
import frameworksDataFr from "@/data/fr/frameworks.json";
import frameworksDataDe from "@/data/de/frameworks.json";
import frameworksDataZh from "@/data/zh-CN/frameworks.json";
import { getLocalizedHref } from "@/i18n/links";
import { ArrowRight, ArrowUpRight, BookOpen, Box, Check, Code, Layers } from "lucide-react";
export default async function FrameworkDetail({ params }) {
const { locale, key } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const currentLocale = isEs ? "es" : isEn ? "en" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const frameworksData = isEs ? frameworksDataEs : isEn ? frameworksDataEn : isFr ? frameworksDataFr : isZh ? frameworksDataZh : isDe ? frameworksDataDe : frameworksDataPt;
const framework = frameworksData[key];
if (!framework) {
notFound();
}
const features = framework.caracteristicas || [];
const useCases = framework.casos_uso || [];
const isEspIdf = key === "ESP-IDF";
return (
<div className="site-canvas min-h-screen">
{/* Ficha técnica do framework e trilha de navegação para o Google */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.framework(key, framework, currentLocale)) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.trilha([
{ nome: isEs ? "Inicio" : isEn ? "Home" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: "Frameworks", caminho: getLocalizedHref("/frameworks", currentLocale) },
{ nome: framework.nome, caminho: getLocalizedHref(`/frameworks/${encodeURIComponent(key)}`, currentLocale) },
])),
}}
/>
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Frameworks y SDKs" : isEn ? "Frameworks & SDKs" : isFr ? "Frameworks et SDKs" : isZh ? "框架与 SDK" : isDe ? "Frameworks & SDKs" : "Frameworks e SDKs", href: getLocalizedHref("/frameworks", currentLocale) }, { label: framework.nome }]}
icon={Layers}
label={framework.tipo}
title={framework.nome}
lede={framework.descricao}
>
{framework.documentacao && (
<a href={framework.documentacao} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
<BookOpen className="h-4 w-4" aria-hidden="true" />
{isEs ? "Documentación oficial" : isEn ? "Official documentation" : isFr ? "Documentation officielle" : isZh ? "官方文档" : isDe ? "Offizielle Dokumentation" : "Documentação oficial"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
{framework.repositorio && (
<a href={framework.repositorio} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
<Code className="h-4 w-4" aria-hidden="true" />
{isEs ? "Repositorio en GitHub" : isEn ? "GitHub repository" : isFr ? "Dépôt sur GitHub" : isZh ? "GitHub 仓库" : isDe ? "GitHub-Repository" : "Repositório no GitHub"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
</PageHero>
<section className="shell mt-10" aria-label={isEs ? "Resumen" : isEn ? "Summary" : isFr ? "Résumé" : isZh ? "概览" : isDe ? "Übersicht" : "Resumo"}>
<dl className="grid gap-3 md:grid-cols-3">
<div className="tile">
<dt className="text-xs font-medium text-muted">{isEs ? "Lenguaje" : isEn ? "Language" : isFr ? "Langage" : isZh ? "语言" : isDe ? "Sprache" : "Linguagem"}</dt>
<dd className="mt-1 font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{framework.linguagem}</dd>
<dd className="mt-0.5 text-xs text-muted">{framework.nome_completo}</dd>
</div>
<div className="tile">
<dt className="text-xs font-medium text-muted">{isEs ? "Categoría" : isEn ? "Category" : isFr ? "Catégorie" : isZh ? "类别" : isDe ? "Kategorie" : "Categoria"}</dt>
<dd className="mt-1 font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{framework.tipo}</dd>
</div>
<div className="tile">
<dt className="text-xs font-medium text-muted">{isEs ? "Objetivo principal" : isEn ? "Main purpose" : isFr ? "Objectif principal" : isZh ? "主要目标" : isDe ? "Hauptzweck" : "Objetivo principal"}</dt>
<dd className="mt-1 text-sm font-medium leading-relaxed text-ink">{framework.funcao_principal}</dd>
</div>
</dl>
</section>
<section className="shell mt-12 grid gap-5 lg:grid-cols-2" aria-label={isEs ? "Funciones y aplicaciones" : isEn ? "Features and applications" : isFr ? "Fonctionnalités et applications" : isZh ? "功能与应用" : isDe ? "Features und Anwendungen" : "Recursos e aplicações"}>
<div className="card p-5 sm:p-7">
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">
{isEs ? "Funciones destacadas" : isEn ? "Key features" : isFr ? "Fonctionnalités clés" : isZh ? "亮点功能" : isDe ? "Wichtigste Features" : "Recursos de destaque"}
</h2>
<ul className="mt-5 space-y-3">
{features.map((feature) => (
<li key={feature} className="flex items-start gap-3 text-sm leading-relaxed text-ink-soft">
<Check className="mt-0.5 h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
{feature}
</li>
))}
</ul>
</div>
<div className="card p-5 sm:p-7">
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">
{isEs ? "Cuándo usar" : isEn ? "When to use" : isFr ? "Quand l'utiliser" : isZh ? "适用场景" : isDe ? "Einsatzbereiche" : "Quando usar"}
</h2>
<ul className="mt-5 space-y-2.5">
{useCases.map((useCase) => (
<li key={useCase} className="tile text-sm font-medium text-ink-soft">
{useCase}
</li>
))}
</ul>
</div>
</section>
{isEspIdf && (
<section className="shell mt-8">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<span className="chip chip-accent">
<Box className="h-3.5 w-3.5" aria-hidden="true" />
{isEs ? "ESP-IDF 4.4 o superior" : isEn ? "ESP-IDF 4.4 or higher" : isFr ? "ESP-IDF 4.4 ou supérieur" : isZh ? "ESP-IDF 4.4 或更高版本" : isDe ? "ESP-IDF 4.4 oder höher" : "ESP-IDF 4.4 ou superior"}
</span>
<h2 className="section-title mt-4">
{isEs ? "Módulos con ESP Component Registry" : isEn ? "Modules with the ESP Component Registry" : isFr ? "Modules avec l'ESP Component Registry" : isZh ? "借助 ESP Component Registry 使用模块" : isDe ? "Module mit der ESP Component Registry" : "Módulos com o ESP Component Registry"}
</h2>
<p className="mt-3 text-base leading-relaxed text-muted">
{isEs ? (
<>
En los proyectos ESP-IDF v4.4+ y v5.x, las bibliotecas ya no necesitan agregarse como submódulos Git. Utilice el{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> y el comando{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code> para descargar controladores de pantalla (LVGL), pilas industriales (Modbus), RainMaker y más.
</>
) : isEn ? (
<>
In ESP-IDF v4.4+ and v5.x projects, libraries no longer need to be added as Git submodules. Use{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> and the command{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code> to download display drivers (LVGL), industrial stacks (Modbus), RainMaker, and more.
</>
) : isFr ? (
<>
Dans les projets ESP-IDF v4.4+ et v5.x, les bibliothèques n'ont plus besoin d'être ajoutées comme sous-modules Git. Utilisez le fichier{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> et la commande{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code> pour télécharger des pilotes d'écran (LVGL), des piles industrielles (Modbus), RainMaker et bien plus encore.
</>
) : isZh ? (
<>
在 ESP-IDF v4.4+ 和 v5.x 项目中,库不再需要以 Git 子模块的方式引入。使用{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> 和命令{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code>,即可下载显示驱动(LVGL)、工业协议栈(Modbus)、RainMaker 等。
</>
) : isDe ? (
<>
In Projekten mit ESP-IDF v4.4+ und v5.x müssen Bibliotheken nicht mehr als Git-Submodule eingebunden werden. Nutzen Sie{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> und den Befehl{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code>, um Display-Treiber (LVGL), Industrieprotokolle (Modbus), RainMaker und mehr herunterzuladen.
</>
) : (
<>
Nos projetos ESP-IDF v4.4+ e v5.x, as bibliotecas não precisam mais entrar como submódulos Git. Use o{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> e o comando{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code> para baixar drivers de display (LVGL), pilhas industriais (Modbus), RainMaker e mais.
</>
)}
</p>
</div>
<Link href={getLocalizedHref("/componentes", currentLocale)} className="btn btn-primary shrink-0">
{isEs ? "Explorar componentes" : isEn ? "Explore components" : isFr ? "Explorer les composants" : isZh ? "探索组件" : isDe ? "Komponenten erkunden" : "Explorar componentes"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
)}
{framework.exemplo && (
<section className="shell mt-8">
<CodeExample framework={framework} />
</section>
)}
<div className="shell section pt-10">
<Link href={getLocalizedHref("/frameworks", currentLocale)} className="inline-flex min-h-11 items-center gap-2 text-sm font-medium text-accent hover:text-accent-strong">
<ArrowRight className="h-4 w-4 rotate-180" aria-hidden="true" />
{isEs ? "Ver todos los frameworks" : isEn ? "View all frameworks" : isFr ? "Voir tous les frameworks" : isZh ? "查看全部框架" : isDe ? "Alle Frameworks ansehen" : "Ver todos os frameworks"}
</Link>
</div>
</main>
<Footer />
</div>
);
}
export async function generateMetadata({ params }) {
const { locale, key } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const currentLocale = isEs ? "es" : isEn ? "en" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const frameworksData = isEs ? frameworksDataEs : isEn ? frameworksDataEn : isFr ? frameworksDataFr : isZh ? frameworksDataZh : isDe ? frameworksDataDe : frameworksDataPt;
const framework = frameworksData[key];
if (!framework) {
return { title: isEs ? "Framework no encontrado" : isEn ? "Framework not found" : isFr ? "Framework introuvable" : isZh ? "未找到该框架" : isDe ? "Framework nicht gefunden" : "Framework não encontrado", robots: { index: false, follow: false } };
}
return {
...paginaMeta({
titulo: isEs ? `${framework.nome} para ESP32 · Guía técnica` : isEn ? `${framework.nome} for ESP32 · Technical Guide` : isFr ? `${framework.nome} pour ESP32 · Guide technique` : isZh ? `用于 ESP32 的 ${framework.nome}:技术指南` : isDe ? `${framework.nome} für ESP32 · Technischer Leitfaden` : `${framework.nome} para ESP32 · Guia Técnico`,
descricao: isEs
? `${framework.nome_completo}: ${framework.descricao} Guía con ejemplos prácticos de código y casos de uso.`
: isEn
? `${framework.nome_completo}: ${framework.descricao} Guide with practical code examples and use cases.`
: isFr
? `${framework.nome_completo} : ${framework.descricao} Guide avec exemples pratiques de code et cas d'usage.`
: isZh ? `${framework.nome_completo}:${framework.descricao} 附实用代码示例与使用场景的指南。` : isDe
? `${framework.nome_completo}: ${framework.descricao} Leitfaden mit praktischen Codebeispielen und Anwendungsfällen.`
: `${framework.nome_completo}: ${framework.descricao} Guia com exemplos práticos de código e casos de uso.`,
caminho: `/frameworks/${encodeURIComponent(key)}`,
tipo: "article",
locale: currentLocale,
keywords: isEs
? [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `programar ESP32 con ${framework.nome}`,
"ESP32", "framework ESP32",
]
: isEn
? [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `program ESP32 with ${framework.nome}`,
"ESP32", "ESP32 framework",
]
: isFr
? [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `programmer ESP32 avec ${framework.nome}`,
"ESP32", "framework ESP32",
]
: isZh ? [ framework.nome, framework.nome_completo, `${framework.nome} ESP32`, `用 ${framework.nome} 开发 ESP32`, "ESP32", "ESP32 框架", ] : isDe
? [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `ESP32 programmieren mit ${framework.nome}`,
"ESP32", "ESP32 Framework",
]
: [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `programar ESP32 com ${framework.nome}`,
"ESP32", "framework ESP32",
],
}),
other: { "article:section": "Frameworks" },
};
}
export async function generateStaticParams() {
return Object.keys(frameworksDataPt).map((key) => ({
key: key,
}));
}
+128
View File
@@ -0,0 +1,128 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return {
...paginaMeta({
titulo: isEs
? "Frameworks y SDKs para ESP32: Guía completa y comparativa"
: isEn
? "ESP32 Frameworks & SDKs: Complete Guide and Comparison"
: isFr
? "Frameworks et SDKs pour ESP32 : guide complet et comparatif"
: isZh ? "ESP32 框架与 SDK:完整指南与对比" : isDe
? "ESP32-Frameworks & SDKs: Vollständiger Leitfaden und Vergleich"
: "Frameworks & SDKs para ESP32: Guia Completo e Comparativo",
descricao: isEs
? "Guía completa de desarrollo: ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino y MicroPython con ejemplos de código."
: isEn
? "Complete development guide: ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino, and MicroPython with code examples."
: isFr
? "Guide complet de développement : ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino et MicroPython avec exemples de code."
: isZh ? "完整开发指南:ESP-IDF、ESP-RainMaker、ESP-Matter、Rust、ESP-ADF、ESP-SR、ESP-WHO、Arduino 和 MicroPython,附代码示例。" : isDe
? "Vollständiger Entwicklungsleitfaden: ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino und MicroPython mit Codebeispielen."
: "Guia completo de desenvolvimento: ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino e MicroPython com exemplos de código.",
caminho: "/frameworks",
locale,
keywords: isEs
? [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"frameworks ESP32",
"programar ESP32",
]
: isEn
? [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"frameworks ESP32",
"program ESP32",
]
: isFr
? [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"frameworks ESP32",
"programmer ESP32",
]
: isZh ? ["ESP-IDF", "ESP-RainMaker", "ESP-Matter", "Rust ESP32", "ESP-SR", "ESP-ADF", "ESP-IoT-Solution", "Arduino ESP32", "MicroPython ESP32", "ESP32 框架", "ESP32 编程"] : isDe
? [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"ESP32 Frameworks",
"ESP32 programmieren",
]
: [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"frameworks ESP32",
"programar ESP32",
],
}),
};
}
export default async function FrameworksLayout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEs ? "Inicio" : isEn ? "Home" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: "Frameworks", caminho: isEs ? "/es/frameworks" : isEn ? "/en/frameworks" : isFr ? "/fr/frameworks" : isZh ? "/zh-CN/frameworks" : isDe ? "/de/frameworks" : "/frameworks" },
])
),
}}
/>
{children}
</>
);
}
+361
View File
@@ -0,0 +1,361 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import SectionHead from "@/components/SectionHead";
import Link from "next/link";
import frameworksDataPt from "@/public/frameworks.json";
import frameworksDataEn from "@/data/en/frameworks.json";
import frameworksDataEs from "@/data/es/frameworks.json";
import frameworksDataFr from "@/data/fr/frameworks.json";
import frameworksDataDe from "@/data/de/frameworks.json";
import frameworksDataZh from "@/data/zh-CN/frameworks.json";
import { paginaMeta } from "@/lib/seo";
import { getLocalizedHref } from "@/i18n/links";
import { ArrowRight, ArrowUpRight, Box, Brain, Cloud, GraduationCap, Layers, Mic, Music, Sparkles } from "lucide-react";
const GUIAS_PT = [
{
icon: GraduationCap,
titulo: "Estou começando",
texto: "Arduino ou MicroPython são os caminhos mais rápidos para testar sensores e APIs. Para produto, vá de ESP-IDF ou Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Nuvem e casa conectada",
texto: "ESP-Matter para interoperabilidade, ESP-RainMaker para nuvem pronta e Zigbee para redes locais de baixo consumo.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Áudio, voz e IA",
texto: "ESP-ADF para áudio, ESP-SR para reconhecimento de fala offline e ESP-NN para acelerar TinyML.",
links: [
["Áudio", "/frameworks/ESP-ADF", Music],
["Voz", "/frameworks/ESP-SR", Mic],
["IA", "/frameworks/ESP-NN", Brain],
],
},
];
const GUIAS_EN = [
{
icon: GraduationCap,
titulo: "Getting Started",
texto: "Arduino or MicroPython are the fastest routes to test sensors and APIs. For production, go with ESP-IDF or Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Cloud and Connected Home",
texto: "ESP-Matter for interoperability, ESP-RainMaker for ready-made cloud, and Zigbee for low-power local mesh networks.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Audio, Voice and AI",
texto: "ESP-ADF for audio processing, ESP-SR for offline speech recognition, and ESP-NN for accelerating TinyML.",
links: [
["Audio", "/frameworks/ESP-ADF", Music],
["Voice", "/frameworks/ESP-SR", Mic],
["AI", "/frameworks/ESP-NN", Brain],
],
},
];
const GUIAS_ES = [
{
icon: GraduationCap,
titulo: "Estoy comenzando",
texto: "Arduino o MicroPython son los caminos más rápidos para probar sensores y APIs. Para producto, elija ESP-IDF o Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Nube y hogar conectado",
texto: "ESP-Matter para interoperabilidad, ESP-RainMaker para nube lista y Zigbee para redes locales de bajo consumo.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Audio, voz e IA",
texto: "ESP-ADF para procesamiento de audio, ESP-SR para reconocimiento de voz offline y ESP-NN para acelerar TinyML.",
links: [
["Audio", "/frameworks/ESP-ADF", Music],
["Voz", "/frameworks/ESP-SR", Mic],
["IA", "/frameworks/ESP-NN", Brain],
],
},
];
const GUIAS_FR = [
{
icon: GraduationCap,
titulo: "Je débute",
texto: "Arduino ou MicroPython sont les voies les plus rapides pour tester capteurs et APIs. Pour la production, optez pour ESP-IDF ou Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Cloud et maison connectée",
texto: "ESP-Matter pour l'interopérabilité, ESP-RainMaker pour un cloud clé en main et Zigbee pour les réseaux maillés locaux à basse consommation.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Audio, voix et IA",
texto: "ESP-ADF pour le traitement audio, ESP-SR pour la reconnaissance vocale hors ligne et ESP-NN pour accélérer le TinyML.",
links: [
["Audio", "/frameworks/ESP-ADF", Music],
["Voix", "/frameworks/ESP-SR", Mic],
["IA", "/frameworks/ESP-NN", Brain],
],
},
];
const GUIAS_DE = [
{
icon: GraduationCap,
titulo: "Erste Schritte",
texto: "Arduino oder MicroPython sind die schnellsten Wege, um Sensoren und APIs zu testen. Für den Produkteinsatz empfehlen sich ESP-IDF oder Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Cloud und Smart Home",
texto: "ESP-Matter für Interoperabilität, ESP-RainMaker für eine fertige Cloud-Lösung und Zigbee für stromsparende lokale Mesh-Netzwerke.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Audio, Sprache und KI",
texto: "ESP-ADF für Audioverarbeitung, ESP-SR für Offline-Sprachkennung und ESP-NN zur Beschleunigung von TinyML.",
links: [
["Audio", "/frameworks/ESP-ADF", Music],
["Sprache", "/frameworks/ESP-SR", Mic],
["KI", "/frameworks/ESP-NN", Brain],
],
},
];
const GUIAS_ZH = [
{
icon: GraduationCap,
titulo: "快速上手",
texto: "Arduino 或 MicroPython 是测试传感器和 API 最快的途径。量产请选择 ESP-IDF 或 Rust。",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "云与智能家居",
texto: "需要互操作用 ESP-Matter,想要现成的云用 ESP-RainMaker,做低功耗本地 Mesh 网络用 Zigbee。",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "音频、语音与 AI",
texto: "音频处理用 ESP-ADF,离线语音识别用 ESP-SR,加速 TinyML 用 ESP-NN。",
links: [
["音频", "/frameworks/ESP-ADF", Music],
["语音", "/frameworks/ESP-SR", Mic],
["AI", "/frameworks/ESP-NN", Brain],
],
},
];
export default async function Frameworks({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const currentLocale = isEs ? "es" : isEn ? "en" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const frameworksData = isEs ? frameworksDataEs : isEn ? frameworksDataEn : isFr ? frameworksDataFr : isZh ? frameworksDataZh : isDe ? frameworksDataDe : frameworksDataPt;
const frameworks = Object.entries(frameworksData);
const guias = isEs ? GUIAS_ES : isEn ? GUIAS_EN : isFr ? GUIAS_FR : isZh ? GUIAS_ZH : isDe ? GUIAS_DE : GUIAS_PT;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Frameworks y SDKs" : isEn ? "Frameworks & SDKs" : isFr ? "Frameworks et SDKs" : isZh ? "框架与 SDK" : isDe ? "Frameworks & SDKs" : "Frameworks e SDKs" }]}
icon={Layers}
label={isEs ? `${frameworks.length} frameworks y SDKs` : isEn ? `${frameworks.length} frameworks and SDKs` : isFr ? `${frameworks.length} frameworks et SDKs` : isZh ? `${frameworks.length} 个框架与 SDK` : isDe ? `${frameworks.length} Frameworks und SDKs` : `${frameworks.length} frameworks e SDKs`}
title={isEs ? "Frameworks y SDKs de ESP32" : isEn ? "ESP32 Frameworks and SDKs" : isFr ? "Frameworks et SDKs pour ESP32" : isZh ? "ESP32 框架与 SDK" : isDe ? "ESP32-Frameworks und SDKs" : "Frameworks e SDKs do ESP32"}
lede={
isEs
? "Desde C/C++ nativo con FreeRTOS hasta Rust, nube IoT, reconocimiento de voz, audio y Matter. Elija según lo que desee construir."
: isEn
? "From native C/C++ with FreeRTOS to Rust, IoT cloud, speech recognition, audio, and Matter. Choose by what you want to build."
: isFr
? "Du C/C++ natif avec FreeRTOS à Rust, en passant par le cloud IoT, la reconnaissance vocale, l'audio et Matter. Choisissez selon ce que vous souhaitez concevoir."
: isZh ? "从原生 C/C++ 与 FreeRTOS,到 Rust,再到物联网云、语音识别、音频和 Matter。按你想构建的东西来选。" : isDe
? "Von nativem C/C++ mit FreeRTOS bis hin zu Rust, IoT-Cloud, Spracherkennung, Audio und Matter. Wählen Sie passend zu Ihrem Projekt."
: "Do C/C++ nativo com FreeRTOS ao Rust, passando por nuvem IoT, reconhecimento de voz, áudio e Matter. Escolha pelo que você quer construir."
}
/>
<section className="shell pt-10 sm:pt-12" aria-label={isEs ? "Por dónde empezar" : isEn ? "Where to begin" : isFr ? "Par où commencer" : isZh ? "从哪里开始" : isDe ? "Wo anfangen" : "Por onde começar"}>
<div className="grid gap-4 md:grid-cols-3">
{guias.map(({ icon: Icon, titulo, texto, links }) => (
<div key={titulo} className="card flex flex-col p-5 sm:p-6">
<span className="grid h-10 w-10 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<h2 className="mt-4 font-display text-xl font-semibold tracking-[-0.03em] text-ink">{titulo}</h2>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{texto}</p>
<ul className="mt-5 flex flex-wrap gap-2 border-t border-line pt-4">
{links.map(([rotulo, href, Extra]) => (
<li key={rotulo}>
<Link href={getLocalizedHref(href, currentLocale)} className="chip-btn">
{Extra && <Extra className="h-4 w-4" aria-hidden="true" />}
{rotulo}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
</section>
<section className="shell mt-10">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<span className="chip chip-accent">
<Box className="h-3.5 w-3.5" aria-hidden="true" />
{isEs ? "Arquitectura modular" : isEn ? "Modular architecture" : isFr ? "Architecture modulaire" : isZh ? "模块化架构" : isDe ? "Modulare Architektur" : "Arquitetura modular"}
</span>
<h2 className="section-title mt-4">ESP Component Registry</h2>
<p className="mt-3 text-base leading-relaxed text-muted">
{isEs ? (
<>
Instale controladores de pantalla (LVGL), pilas industriales (Modbus), integraciones en la nube y paquetes de soporte para placas
(BSPs) con una sola línea en su manifiesto <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code>.
</>
) : isEn ? (
<>
Install display drivers (LVGL), industrial stacks (Modbus), cloud integrations, and board support packages
(BSPs) with a single line in your <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> manifest.
</>
) : isFr ? (
<>
Installez des pilotes d'écran (LVGL), des piles industrielles (Modbus), des fonctionnalités cloud et des paquets de support de cartes
(BSPs) avec une seule ligne dans votre manifeste <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code>.
</>
) : isZh ? ( <>
通过 <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> 清单中的一行,即可安装显示驱动(LVGL)、工业协议栈(Modbus)、云功能和开发板包(BSP)。
</> ) : isDe ? (
<>
Installieren Sie Display-Treiber (LVGL), Industrieprotokolle (Modbus), Cloud-Funktionen und Board-Support-Pakete
(BSPs) mit einer einzigen Zeile in Ihrem <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code>-Manifest.
</>
) : (
<>
Instale drivers de display (LVGL), pilhas industriais (Modbus), recursos de nuvem e pacotes de placa
(BSPs) com uma linha no manifesto <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code>.
</>
)}
</p>
</div>
<Link href={getLocalizedHref("/componentes", currentLocale)} className="btn btn-primary shrink-0">
{isEs ? "Explorar componentes" : isEn ? "Explore components" : isFr ? "Explorer les composants" : isZh ? "探索组件" : isDe ? "Komponenten erkunden" : "Explorar componentes"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
<section className="shell section" aria-labelledby="todos-titulo">
<SectionHead
id="todos-titulo"
eyebrow={isEs ? "Todos" : isEn ? "All" : "Todos"}
title={isEs ? "Todos los frameworks" : isEn ? "All frameworks" : isFr ? "Tous les frameworks" : isZh ? "全部框架" : isDe ? "Alle Frameworks" : "Todos os frameworks"}
lede={isEs ? "Cada ficha ofrece funciones, aplicaciones ideales, ejemplos de código y enlaces oficiales." : isEn ? "Each page provides features, ideal use cases, code examples, and official links." : isFr ? "Chaque fiche présente les fonctionnalités, les cas d'usage idéaux, des exemples de code et les liens officiels." : isZh ? "每张卡片包含功能、理想应用场景、代码示例和官方链接。" : isDe ? "Jedes Datenblatt bietet Features, ideale Anwendungsbereiche, Codebeispiele und offizielle Links." : "Cada ficha traz recursos, aplicações ideais, exemplo de código e links oficiais."}
/>
<div className="mt-8 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{frameworks.map(([key, framework]) => (
<Link key={key} href={getLocalizedHref(`/frameworks/${encodeURIComponent(key)}`, currentLocale)} className="card card-interactive group flex flex-col p-5 sm:p-6">
<div className="flex flex-wrap items-start justify-between gap-2">
<h3 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">{framework.nome}</h3>
<span className="chip max-w-full">{framework.linguagem}</span>
</div>
<p className="mt-1 text-sm text-muted">{framework.tipo}</p>
<p className="mt-3 line-clamp-3 text-sm leading-relaxed text-muted">{framework.descricao}</p>
<ul className="mt-5 flex flex-1 flex-wrap content-start gap-1.5">
{framework.casos_uso.slice(0, 3).map((caso) => (
<li key={caso} className="chip max-w-full">
<span className="truncate">{caso}</span>
</li>
))}
</ul>
<span className="mt-5 inline-flex items-center gap-1 border-t border-line pt-4 text-sm font-medium text-accent">
{isEs ? "Ver detalles y ejemplo" : isEn ? "View details and example" : isFr ? "Voir les détails et l'exemple" : isZh ? "查看详情与示例" : isDe ? "Details und Beispiel ansehen" : "Ver detalhes e exemplo"}
<ArrowUpRight className="h-4 w-4 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
))}
</div>
</section>
</main>
<Footer />
</div>
);
}
+142
View File
@@ -0,0 +1,142 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import { categoriasGlossario as categoriasGlossarioPt } from "@/lib/glossarioData";
import { categoriasGlossario as categoriasGlossarioEn } from "@/lib/data/en/glossario.js";
import { categoriasGlossario as categoriasGlossarioEs } from "@/lib/data/es/glossario.js";
import { categoriasGlossario as categoriasGlossarioFr } from "@/lib/data/fr/glossario.js";
import { categoriasGlossario as categoriasGlossarioDe } from "@/lib/data/de/glossario.js";
import { categoriasGlossario as categoriasGlossarioZh } from "@/lib/data/zh-CN/glossario.js";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isEs
? "Glosario técnico de ESP32: Términos y conceptos"
: isEn
? "ESP32 Technical Glossary: Terms and Concepts"
: isFr
? "Glossaire technique de l'ESP32 : termes et concepts"
: isZh ? "ESP32 技术术语表:术语与概念" : isDe
? "Technisches ESP32-Glossar: Begriffe und Konzepte"
: "Glossário Técnico do ESP32: Termos e Conceitos",
descricao: isEs
? "Más de 50 conceptos esenciales de ESP32 explicados: GPIO, Strapping Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter y Thread."
: isEn
? "Over 50 essential ESP32 concepts explained: GPIO, Strapping Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter, and Thread."
: isFr
? "Plus de 50 concepts essentiels de l'ESP32 expliqués : GPIO, Strapping Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter et Thread."
: isZh ? "50 多个 ESP32 生态的核心术语与概念详解:GPIO、启动配置引脚(Strapping)、ULP、PSRAM、FreeRTOS、eFuse、Deep Sleep、OTA、Secure Boot、ECDSA、Matter 和 Thread。" : isDe
? "Über 50 wichtige ESP32-Konzepte verständlich erklärt: GPIO, Strapping-Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter und Thread."
: "Mais de 50 termos e conceitos essenciais do ecossistema ESP32 explicados em português: GPIO, Strapping Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter e Thread.",
caminho: "/glossario",
locale,
keywords: isEs
? [
"glosario ESP32",
"qué es GPIO",
"qué son strapping pins",
"qué es ESP32 ULP",
"qué es ESP32 PSRAM",
"términos técnicos microcontrolador",
"conceptos ESP32 hardware",
]
: isEn
? [
"ESP32 glossary",
"what is GPIO",
"what are strapping pins",
"what is ESP32 ULP",
"what is ESP32 PSRAM",
"microcontroller technical terms",
"ESP32 hardware concepts",
]
: isFr
? [
"glossaire ESP32",
"qu'est-ce que le GPIO",
"que sont les strapping pins",
"qu'est-ce que l'ESP32 ULP",
"qu'est-ce que l'ESP32 PSRAM",
"termes techniques microcontrôleur",
"concepts matériels ESP32",
]
: isZh ? ["ESP32 术语表", "什么是 GPIO", "什么是启动配置引脚", "什么是 ESP32 ULP", "什么是 ESP32 PSRAM", "微控制器技术术语", "ESP32 概念"] : isDe
? [
"ESP32 Glossar",
"was ist GPIO",
"was sind Strapping-Pins",
"was ist ESP32 ULP",
"was ist ESP32 PSRAM",
"technische Mikrocontroller-Begriffe",
"ESP32 Hardware-Konzepte",
]
: [
"glossário ESP32",
"o que é GPIO",
"o que é strapping pins",
"o que é ULP ESP32",
"o que é PSRAM ESP32",
"termos técnicos microcontrolador",
"conceitos ESP32 português",
],
});
}
export default async function GlossarioLayout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const categorias = isEs ? categoriasGlossarioEs : isEn ? categoriasGlossarioEn : isFr ? categoriasGlossarioFr : isZh ? categoriasGlossarioZh : isDe ? categoriasGlossarioDe : categoriasGlossarioPt;
const canonPath = isEs ? "/es/glosario" : isEn ? "/en/glossary" : isFr ? "/fr/glossaire" : isZh ? "/zh-CN/glossary" : isDe ? "/de/glossar" : "/glossario";
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.glossario(categorias, locale)),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isEs ? "Inicio" : isEn ? "Home" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/" },
{ nome: isEs ? "Glosario técnico" : isEn ? "Technical Glossary" : isFr ? "Glossaire technique" : isZh ? "技术术语表" : isDe ? "Technisches Glossar" : "Glossário Técnico", caminho: canonPath },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isEs ? "Glosario técnico de ESP32" : isEn ? "ESP32 Technical Glossary" : isFr ? "Glossaire technique de l'ESP32" : isZh ? "ESP32 技术术语表" : isDe ? "Technisches ESP32-Glossar" : "Glossário Técnico do ESP32",
descricao: isEs
? "Enciclopedia de términos técnicos y conceptos de hardware y software del ecosistema ESP32."
: isEn
? "Encyclopedia of hardware and software technical terms for the ESP32 ecosystem."
: isFr
? "Encyclopédie des termes techniques et des concepts matériels et logiciels de l'écosystème ESP32."
: isZh ? "ESP32 生态硬件与软件技术术语和概念的百科。" : isDe
? "Enzyklopädie technischer Begriffe und Hardware-/Softwarekonzepte für das ESP32-Ökosystem."
: "Enciclopédia de termos técnicos e conceitos de hardware e software do ecossistema ESP32.",
caminho: canonPath,
locale,
})
),
}}
/>
{children}
</>
);
}
+453
View File
@@ -0,0 +1,453 @@
"use client";
import { useState, useMemo, useRef } from "react";
import { usePathname } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Link from "next/link";
import * as glossarioPt from "@/lib/glossarioData";
import * as glossarioEn from "@/lib/data/en/glossario";
import * as glossarioEs from "@/lib/data/es/glossario";
import * as glossarioFr from "@/lib/data/fr/glossario";
import * as glossarioDe from "@/lib/data/de/glossario";
import * as glossarioZh from "@/lib/data/zh-CN/glossario";
import { getLocalizedHref } from "@/i18n/links";
import {
ArrowRight,
BookOpen,
Check,
Code2,
Cpu,
Database,
HelpCircle,
LayoutGrid,
Lightbulb,
Link2,
BatteryCharging,
RotateCcw,
Search,
ShieldCheck,
Sliders,
Sparkles,
Wifi,
X,
} from "lucide-react";
const BUSCAS_POPULARES = ["GPIO", "ULP", "PSRAM", "Strapping Pins", "Deep Sleep", "OTA", "Matter", "Secure Boot", "Wi-Fi 6", "MIPI"];
const ICONES = { Cpu, Database, Wifi, Sliders, Sparkles, BatteryCharging, Code2, ShieldCheck };
/** "Processamento, CPU & Silício" vira "Processamento": cabe no filtro sem truncar. */
const nomeCurto = (nome) => nome.split(/,| &/)[0].trim();
export default function GlossarioPage() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const currentLocale = isZh ? "zh-CN" : isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt";
const { categoriasGlossario } = isZh ? glossarioZh : isDe ? glossarioDe : isFr ? glossarioFr : isEs ? glossarioEs : isEn ? glossarioEn : glossarioPt;
const [busca, setBusca] = useState("");
const [categoriaSelecionada, setCategoriaSelecionada] = useState("todas");
const [letraFiltro, setLetraFiltro] = useState(null);
const [copiadoSlug, setCopiadoSlug] = useState(null);
const searchInputRef = useRef(null);
const todosOsTermos = useMemo(
() =>
categoriasGlossario.flatMap((cat) =>
cat.termos.map((t) => ({
...t,
categoriaId: cat.id,
categoriaNome: cat.nome,
categoriaIcone: cat.icone,
slug: t.termo.toLowerCase().replace(/[\s()/²]+/g, "-"),
primeiraLetra: t.termo.charAt(0).toUpperCase(),
}))
),
[categoriasGlossario]
);
const alfabeto = useMemo(() => {
const disponiveis = new Set(todosOsTermos.map((t) => t.primeiraLetra));
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((letra) => ({ letra, temTermos: disponiveis.has(letra) }));
}, [todosOsTermos]);
const termosFiltrados = useMemo(() => {
const termoBusca = busca.toLowerCase().trim();
return todosOsTermos.filter((item) => {
const matchCategoria = categoriaSelecionada === "todas" || item.categoriaId === categoriaSelecionada;
const matchLetra = !letraFiltro || item.primeiraLetra === letraFiltro;
const matchBusca =
!termoBusca ||
item.termo.toLowerCase().includes(termoBusca) ||
item.definicao.toLowerCase().includes(termoBusca) ||
item.exemplo.toLowerCase().includes(termoBusca) ||
item.categoriaNome.toLowerCase().includes(termoBusca);
return matchCategoria && matchLetra && matchBusca;
});
}, [todosOsTermos, categoriaSelecionada, letraFiltro, busca]);
const temFiltroAtivo = busca.trim() !== "" || categoriaSelecionada !== "todas" || letraFiltro !== null;
const limparTodosFiltros = () => {
setBusca("");
setCategoriaSelecionada("todas");
setLetraFiltro(null);
searchInputRef.current?.focus();
};
const copiarLinkTermo = (slug) => {
const basePath = getLocalizedHref("/glossario", currentLocale);
navigator.clipboard.writeText(`${window.location.origin}${basePath}#${slug}`);
setCopiadoSlug(slug);
setTimeout(() => setCopiadoSlug(null), 2000);
};
const total = termosFiltrados.length;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isZh ? "术语表" : isDe ? "Glossar" : isFr ? "Glossaire" : isEs ? "Glosario" : isEn ? "Glossary" : "Glossário" }]}
icon={BookOpen}
label={
isZh ? `已解释 ${todosOsTermos.length} 个术语` : isDe
? `${todosOsTermos.length} Begriffe erklärt`
: isFr
? `${todosOsTermos.length} termes expliqués`
: isEs
? `${todosOsTermos.length} términos explicados`
: isEn
? `${todosOsTermos.length} terms explained`
: `${todosOsTermos.length} termos explicados`
}
title={
isZh ? "ESP32 技术术语表" : isDe
? "Technisches Glossar für ESP32"
: isFr
? "Glossaire technique ESP32"
: isEs
? "Glosario técnico de ESP32"
: isEn
? "ESP32 Technical Glossary"
: "Glossário técnico do ESP32"
}
lede={
isZh ? "为生态中的每个术语提供直接定义、硬件参数和实用示例,从 ADC 到 Secure Boot。" : isDe
? "Präzise Definitionen, Hardware-Parameter und praktische Beispiele für jeden Begriff des Ökosystems – von ADC bis Secure Boot."
: isFr
? "Définitions précises, paramètres matériels et exemples pratiques pour chaque terme de l'écosystème, de l'ADC au Secure Boot."
: isEs
? "Definiciones directas, parámetros de hardware y un ejemplo práctico para cada término del ecosistema, desde ADC hasta Secure Boot."
: isEn
? "Direct definitions, hardware parameters, and practical examples for every ecosystem term, from ADC to Secure Boot."
: "Definições diretas, parâmetros de hardware e um exemplo prático para cada termo do ecossistema, de ADC a Secure Boot."
}
/>
<section className="shell pt-10 sm:pt-12" aria-label={isZh ? "搜索与筛选" : isDe ? "Suche und Filter" : isFr ? "Recherche et filtres" : isEs ? "Búsqueda y filtros" : isEn ? "Search and filters" : "Busca e filtros"}>
<div className="panel p-5 sm:p-7">
<div className="relative">
<label htmlFor="busca-glossario" className="sr-only">
{isZh ? "搜索术语、缩写或概念" : isDe ? "Nach Begriff, Abkürzung oder Konzept suchen" : isFr ? "Rechercher un terme, un sigle ou un concept" : isEs ? "Buscar término, sigla o concepto" : isEn ? "Search term, acronym, or concept" : "Buscar termo, sigla ou conceito"}
</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-glossario"
ref={searchInputRef}
type="search"
value={busca}
onChange={(e) => setBusca(e.target.value)}
placeholder={isZh ? "搜索术语、缩写或概念" : isDe ? "Nach Begriff, Abkürzung oder Konzept suchen" : isFr ? "Rechercher un terme, un sigle ou un concept" : isEs ? "Buscar término, sigla o concepto" : isEn ? "Search term, acronym, or concept" : "Buscar termo, sigla ou conceito"}
autoComplete="off"
className={`field pl-12 text-base ${busca ? "pr-28" : "pr-4"}`}
/>
<div className="absolute right-2 top-1/2 -translate-y-1/2">
{busca && (
<button type="button" onClick={() => { setBusca(""); searchInputRef.current?.focus(); }} className="btn btn-ghost btn-sm">
<X className="h-3.5 w-3.5" aria-hidden="true" />
{isZh ? "清除" : isDe ? "Löschen" : isFr ? "Effacer" : isEs ? "Limpiar" : isEn ? "Clear" : "Limpar"}
</button>
)}
</div>
</div>
<div className="mt-4 flex flex-wrap items-center gap-2">
<span className="mr-1 text-sm text-muted">{isZh ? "热门搜索" : isDe ? "Häufig gesucht" : isFr ? "Plus recherchés" : isEs ? "Más buscados" : isEn ? "Popular searches" : "Mais buscados"}</span>
{BUSCAS_POPULARES.map((rotulo) => (
<button
key={rotulo}
type="button"
onClick={() => { setBusca(rotulo); setCategoriaSelecionada("todas"); setLetraFiltro(null); }}
className="chip-btn"
>
{rotulo}
</button>
))}
</div>
<div className="mt-5 border-t border-line pt-5">
<h2 className="text-sm font-semibold text-ink">{isZh ? "类别" : isDe ? "Kategorie" : isFr ? "Catégorie" : isEs ? "Categoría" : isEn ? "Category" : "Categoria"}</h2>
<div className="mt-3 flex flex-wrap gap-2">
<button
type="button"
onClick={() => setCategoriaSelecionada("todas")}
aria-pressed={categoriaSelecionada === "todas"}
className="chip-btn"
>
<LayoutGrid className="h-4 w-4" aria-hidden="true" />
{isZh ? "全部" : isDe ? "Alle" : isFr ? "Toutes" : isEs ? "Todas" : isEn ? "All" : "Todas"}
<span className="tabular-nums opacity-80">{todosOsTermos.length}</span>
</button>
{categoriasGlossario.map((cat) => {
const Icone = ICONES[cat.icone] ?? Cpu;
return (
<button
key={cat.id}
type="button"
onClick={() => setCategoriaSelecionada(cat.id)}
aria-pressed={categoriaSelecionada === cat.id}
className="chip-btn"
>
<Icone className="h-4 w-4" aria-hidden="true" />
{nomeCurto(cat.nome)}
<span className="tabular-nums opacity-80">{cat.termos.length}</span>
</button>
);
})}
</div>
</div>
{/* O filtro A–Z não faz sentido em chinês: os termos começam por ideogramas. */}
{!isZh && (
<div className="mt-6 border-t border-line pt-6">
<h2 className="text-sm font-semibold text-ink">{isZh ? "按字母顺序" : isDe ? "Alphabetische Reihenfolge" : isFr ? "Ordre alphabétique" : isEs ? "Orden alfabético" : isEn ? "Alphabetical order" : "Ordem alfabética"}</h2>
<div className="mt-3 flex flex-wrap gap-1.5" role="group" aria-label={isZh ? "按首字母筛选" : isDe ? "Nach Anfangsbuchstaben filtern" : isFr ? "Filtrer par lettre initiale" : isEs ? "Filtrar por letra inicial" : isEn ? "Filter by first letter" : "Filtrar pela letra inicial"}>
<button type="button" onClick={() => setLetraFiltro(null)} aria-pressed={letraFiltro === null} className="chip-btn">
{isZh ? "全部" : isDe ? "Alle" : isFr ? "Toutes" : isEs ? "Todas" : isEn ? "All" : "Todas"}
</button>
{alfabeto.map(({ letra, temTermos }) => (
<button
key={letra}
type="button"
disabled={!temTermos}
onClick={() => setLetraFiltro(letraFiltro === letra ? null : letra)}
aria-pressed={letraFiltro === letra}
className="chip-btn min-w-[2.25rem] justify-center text-xs"
>
{letra}
</button>
))}
</div>
</div>
)}
</div>
</section>
<section className="shell section pt-8 sm:pt-10" aria-labelledby="resultado-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="resultado-titulo" className="text-base font-semibold text-ink" role="status" aria-live="polite">
{total}{" "}
{total === 1
? isZh ? "个术语" : isDe
? "Begriff"
: isFr
? "terme"
: isEs
? "término"
: isEn
? "term"
: "termo"
: isZh ? "个术语" : isDe
? "Begriffe"
: isFr
? "termes"
: isEs
? "términos"
: isEn
? "terms"
: "termos"}
{temFiltroAtivo && (
<span className="font-normal text-muted">
{isZh ? "(当前筛选下)" : isDe
? " mit den aktuellen Filtern"
: isFr
? " avec les filtres actuels"
: isEs
? " con los filtros actuales"
: isEn
? " with current filters"
: " com os filtros atuais"}
</span>
)}
</h2>
{temFiltroAtivo && (
<button type="button" onClick={limparTodosFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
{isZh ? "重置筛选" : isDe ? "Filter zurücksetzen" : isFr ? "Réinitialiser les filtres" : isEs ? "Restablecer filtros" : isEn ? "Reset filters" : "Redefinir filtros"}
</button>
)}
</div>
{total === 0 ? (
<div className="card mt-6 px-6 py-14 text-center">
<HelpCircle className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">
{isZh ? "未找到术语" : isDe ? "Keine Begriffe gefunden" : isFr ? "Aucun terme trouvé" : isEs ? "No se encontraron términos" : isEn ? "No terms found" : "Nenhum termo encontrado"}
</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
{isZh ? "没有任何术语符合当前的搜索和筛选。请尝试更短的缩写,或重置为全部类别。" : isDe
? "Nichts entspricht Ihrer aktuellen Suche und den Filtern. Versuchen Sie eine kürzere Abkürzung oder wählen Sie alle Kategorien."
: isFr
? "Rien ne correspond à votre recherche et à vos filtres actuels. Essayez avec un sigle plus court ou revenez à toutes les catégories."
: isEs
? "Nada coincide con la búsqueda y los filtros actuales. Pruebe con una sigla más corta o vuelva a todas las categorías."
: isEn
? "Nothing matches your current search and filters. Try a shorter acronym or reset to all categories."
: "Nada combina com a busca e os filtros atuais. Tente uma sigla mais curta ou volte para todas as categorias."}
</p>
<button type="button" onClick={limparTodosFiltros} className="btn btn-primary mt-6">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
{isZh ? "清除筛选" : isDe ? "Filter zurücksetzen" : isFr ? "Réinitialiser les filtres" : isEs ? "Limpiar filtros" : isEn ? "Clear filters" : "Limpar filtros"}
</button>
</div>
) : (
<div className="mt-6 grid gap-4 md:grid-cols-2">
{termosFiltrados.map((item) => {
const Icone = ICONES[item.categoriaIcone] ?? Cpu;
return (
<article key={item.slug} id={item.slug} className="card flex scroll-mt-28 flex-col p-5 sm:p-6">
<div className="flex items-center justify-between gap-3">
<span className="chip">
<Icone className="h-3.5 w-3.5 text-accent" aria-hidden="true" />
{nomeCurto(item.categoriaNome)}
</span>
<button
type="button"
onClick={() => copiarLinkTermo(item.slug)}
aria-label={
isZh ? `复制 ${item.termo} 的链接` : isDe
? `Link für ${item.termo} kopieren`
: isFr
? `Copier le lien pour ${item.termo}`
: isEs
? `Copiar enlace para ${item.termo}`
: isEn
? `Copy link for ${item.termo}`
: `Copiar link para ${item.termo}`
}
className="btn-icon inline-flex h-11 w-11 items-center justify-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-accent"
>
{copiadoSlug === item.slug ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Link2 className="h-4 w-4" aria-hidden="true" />}
</button>
</div>
<h3 className="mt-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">{item.termo}</h3>
<p className="mt-2 text-[0.9375rem] leading-relaxed text-muted">
<TextoComLinks texto={item.definicao} currentLocale={currentLocale} />
</p>
<div className="callout mt-5">
<p className="flex items-center gap-1.5 text-sm font-semibold text-ink">
<Lightbulb className="h-4 w-4 text-accent" aria-hidden="true" />
{isZh ? "实际应用" : isDe ? "In der Praxis" : isFr ? "En pratique" : isEs ? "En la práctica" : isEn ? "In practice" : "Na prática"}
</p>
<p className="mt-1">
<TextoComLinks texto={item.exemplo} currentLocale={currentLocale} />
</p>
</div>
</article>
);
})}
</div>
)}
</section>
<section className="shell pb-20 md:pb-28">
<div className="panel p-8 text-center sm:p-12">
<h2 className="section-title mx-auto max-w-2xl">
{isZh ? "从概念到合适的芯片。" : isDe ? "Vom Konzept zum richtigen Chip." : isFr ? "Du concept à la bonne puce." : isEs ? "Del concepto al chip adecuado." : isEn ? "From concept to the right chip." : "Do conceito ao chip certo."}
</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
{isZh ? "掌握这些术语后,可以并排对比各系列,或回答选型问题,找到适合你项目的型号。" : isDe
? "Mit den Begriffen zur Hand vergleichen Sie die Serien Seite an Seite oder nutzen Sie die Auswahlhilfe, um das Modell für Ihr Projekt zu finden."
: isFr
? "Avec les termes sous la main, comparez les séries côte à côte ou répondez au sélecteur pour trouver le modèle adapté à votre projet."
: isEs
? "Con los términos a mano, compare las series lado a lado o responda al selector para encontrar el modelo que se adapta a su proyecto."
: isEn
? "With the terms in hand, compare series side by side or answer the selector to find the model that fits your project."
: "Com os termos em mãos, compare as séries lado a lado ou responda ao seletor para chegar ao modelo que cabe no seu projeto."}
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href={getLocalizedHref("/seletor", currentLocale)} className="btn btn-primary w-full sm:w-auto">
<Sliders className="h-4 w-4" aria-hidden="true" />
{isZh ? "选择我的芯片" : isDe ? "Meinen Chip wählen" : isFr ? "Choisir ma puce" : isEs ? "Elegir mi chip" : isEn ? "Choose my chip" : "Escolher meu chip"}
</Link>
<Link href={getLocalizedHref("/series", currentLocale)} className="btn btn-ghost w-full sm:w-auto">
{isZh ? "浏览系列" : isDe ? "Serien erkunden" : isFr ? "Explorer les séries" : isEs ? "Explorar las series" : isEn ? "Explore series" : "Explorar as séries"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
/**
* Função utilitária que detecta nomes de séries do ESP32 dentro do texto e os converte em links clicáveis.
*/
function TextoComLinks({ texto, currentLocale = "pt" }) {
if (!texto) return null;
const seriesKeys = [
"ESP32-S31",
"ESP32-C61",
"ESP32-S2",
"ESP32-S3",
"ESP32-C2",
"ESP32-C3",
"ESP32-C5",
"ESP32-C6",
"ESP32-P4",
"ESP32-H2",
"ESP32-H4",
"ESP32",
];
const regex = new RegExp(`\\b(${seriesKeys.join("|")})\\b`, "g");
const partes = texto.split(regex);
return (
<>
{partes.map((parte, i) => {
if (seriesKeys.includes(parte)) {
return (
<Link
key={i}
href={getLocalizedHref(`/series/${parte}`, currentLocale)}
className="font-semibold text-accent underline decoration-accent/30 underline-offset-2 hover:decoration-accent"
>
{parte}
</Link>
);
}
return parte;
})}
</>
);
}
+245
View File
@@ -0,0 +1,245 @@
import { notFound } from "next/navigation";
import { JetBrains_Mono, Manrope, Space_Grotesk } from "next/font/google";
import { NextIntlClientProvider } from "next-intl";
import { getMessages } from "next-intl/server";
import { routing } from "@/i18n/routing";
import { ENABLED_LOCALES } from "@/i18n/links";
import "../globals.css";
import Providers from "@/components/Providers";
import { SITE, jsonLd } from "@/lib/seo";
const spaceGrotesk = Space_Grotesk({
subsets: ["latin"],
variable: "--font-space-grotesk",
display: "swap",
weight: ["500", "600", "700"],
});
const manrope = Manrope({
subsets: ["latin"],
variable: "--font-manrope",
display: "swap",
weight: ["400", "500", "600", "700"],
});
const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains",
display: "swap",
weight: ["400", "500", "600"],
});
const LANG_MAP = {
pt: "pt-BR",
en: "en",
es: "es-419",
fr: "fr",
de: "de",
"zh-CN": "zh-CN",
};
export function generateStaticParams() {
return ENABLED_LOCALES.map((locale) => ({ locale }));
}
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const ogLocaleMap = {
pt: "pt_BR",
en: "en_US",
es: "es_419",
fr: "fr_FR",
de: "de_DE",
"zh-CN": "zh_CN",
};
const alternateLocales = ENABLED_LOCALES.filter((l) => l !== locale).map((l) => ogLocaleMap[l]);
const titleDefault = isEn
? "ESPDocs · ESP32 Open Documentation"
: isEs
? "ESPDocs · Documentación abierta de ESP32"
: isFr
? "ESPDocs · Documentation ouverte ESP32"
: isZh ? "ESPDocs · ESP32 中文文档" : isDe
? "ESPDocs · Offene ESP32-Dokumentation"
: "ESPDocs · Documentação do ESP32 em português";
const description = isEn
? "Specifications, pinouts, comparison and selection of 12 ESP32 microcontroller series. Datasheets, peripherals, hardware security and connection diagrams."
: isEs
? "Especificaciones, patillaje, comparación y selección de las 12 series de microcontroladores ESP32. Hojas de datos, periféricos, seguridad en hardware y diagramas de conexión."
: isFr
? "Spécifications, brochages, comparaison et sélection des 12 séries de microcontrôleurs ESP32. Fiches techniques, périphériques, sécurité matérielle et schémas de connexion."
: isZh ? "ESP32 全部 12 个系列微控制器的规格、引脚、对比与选型,使用简体中文。含数据手册、外设、硬件安全与连接图。" : isDe
? "Spezifikationen, Pinbelegungen, Vergleich und Auswahl der 12 ESP32-Mikrocontrollerserien. Datenblätter, Peripheriegeräte, Hardwaresicherheit und Anschlussdiagramme."
: "Especificações, pinagem, comparação e seleção das 12 séries de microcontroladores ESP32, em português brasileiro. Datasheets, periféricos, segurança em hardware e diagramas de conexão.";
const keywords = isEn
? [
"ESP32", "ESP32 documentation", "ESP32 pinout",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"compare ESP32", "which ESP32 to choose", "ESP32 datasheet",
"microcontroller", "Espressif", "ESP-IDF", "IoT", "embedded systems",
]
: isEs
? [
"ESP32", "ESP32 en español", "documentación ESP32", "patillaje ESP32", "pinout ESP32",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"comparar ESP32", "cuál ESP32 elegir", "datasheet ESP32", "hoja de datos ESP32",
"microcontrolador", "Espressif", "ESP-IDF", "IoT", "sistemas embebidos",
]
: isFr
? [
"ESP32", "ESP32 en français", "documentation ESP32", "brochage ESP32", "pinout ESP32",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"comparer ESP32", "quel ESP32 choisir", "datasheet ESP32", "fiche technique ESP32",
"microcontrôleur", "Espressif", "ESP-IDF", "IoT", "systèmes embarqués",
]
: isZh ? ["ESP32", "ESP32 中文", "ESP32 文档", "ESP32 引脚图", "ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2", "ESP32 对比", "ESP32 怎么选", "ESP32 数据手册", "微控制器", "乐鑫", "ESP-IDF", "物联网", "嵌入式系统"] : isDe
? [
"ESP32", "ESP32 auf Deutsch", "ESP32 Dokumentation", "ESP32 Pinbelegung", "ESP32 Pinout",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"ESP32 vergleichen", "welchen ESP32 wählen", "ESP32 Datenblatt",
"Mikrocontroller", "Espressif", "ESP-IDF", "IoT", "eingebettete Systeme",
]
: [
"ESP32", "ESP32 português", "documentação ESP32", "pinout ESP32",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"comparar ESP32", "qual ESP32 escolher", "datasheet ESP32",
"microcontrolador", "Espressif", "ESP-IDF", "IoT", "sistemas embarcados",
];
const languages = Object.fromEntries(
ENABLED_LOCALES.map((l) => [LANG_MAP[l] || l, `/${l}`])
);
if (ENABLED_LOCALES.includes("en")) {
languages["x-default"] = "/en";
}
return {
metadataBase: new URL(SITE.url),
title: {
default: titleDefault,
template: "%s · ESPDocs",
},
description,
applicationName: "ESPDocs",
authors: [{ name: "Lucas Rayan Guerra", url: "https://lucasrguerra.dev.br" }],
creator: "Lucas Rayan Guerra",
publisher: "Ciência Embarcada",
category: "technology",
keywords,
alternates: {
canonical: `/${locale}`,
languages,
},
openGraph: {
type: "website",
locale: ogLocaleMap[locale] || "pt_BR",
alternateLocale: alternateLocales.length > 0 ? alternateLocales : undefined,
url: `${SITE.url}/${locale}`,
siteName: SITE.nome,
title: titleDefault,
description: isEn
? "Specifications, pinouts, comparison and selection of 12 ESP32 microcontroller series."
: isEs
? "Especificaciones, patillaje, comparación y selección de las 12 series de microcontroladores ESP32."
: isFr
? "Spécifications, brochages, comparaison et sélection des 12 séries de microcontrôleurs ESP32."
: isZh ? "ESP32 全部 12 个系列微控制器的规格、引脚、对比与选型,使用简体中文。" : isDe
? "Spezifikationen, Pinbelegungen, Vergleich und Auswahl der 12 ESP32-Mikrocontrollerserien."
: "Especificações, pinagem, comparação e seleção das 12 séries de microcontroladores ESP32, em português brasileiro.",
},
twitter: {
card: "summary_large_image",
title: titleDefault,
description: isEn
? "Specifications, pinouts, comparison and selection of 12 ESP32 series."
: isEs
? "Especificaciones, patillaje, comparación y selección de las 12 series de ESP32."
: isFr
? "Spécifications, brochages, comparaison et sélection des 12 séries ESP32."
: isZh ? "ESP32 全部 12 个系列的规格、引脚、对比与选型,使用简体中文。" : isDe
? "Spezifikationen, Pinbelegungen, Vergleich und Auswahl der 12 ESP32-Serien."
: "Especificações, pinagem, comparação e seleção das 12 séries de ESP32, em português.",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-image-preview": "large",
"max-snippet": -1,
"max-video-preview": -1,
},
},
icons: {
icon: [
{ url: "/favicon.ico", sizes: "48x48", type: "image/x-icon" },
{ url: "/favicon-48x48.png", sizes: "48x48", type: "image/png" },
{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" },
{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" },
{ url: "/icon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/icon-512.png", sizes: "512x512", type: "image/png" },
{ url: "/icon.svg", type: "image/svg+xml" },
],
apple: [
{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" },
],
shortcut: "/favicon.ico",
},
manifest: "/site.webmanifest",
formatDetection: { telephone: false, address: false, email: false },
};
}
export const viewport = {
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#f5f6f8" },
{ media: "(prefers-color-scheme: dark)", color: "#07090d" },
],
};
export default async function RootLayout({ children, params }) {
const { locale } = await params;
if (!ENABLED_LOCALES.includes(locale)) {
notFound();
}
const lang = LANG_MAP[locale] || locale;
const messages = await getMessages();
return (
<html lang={lang} className={`${spaceGrotesk.variable} ${manrope.variable} ${jetbrainsMono.variable}`} suppressHydrationWarning>
<head>
{/* Dados estruturados do site e da organização. É o que permite ao
Google montar o box de busca interna e entender a autoria. */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.siteESociedade(locale)) }}
/>
</head>
<body className="font-sans antialiased bg-canvas text-ink overflow-x-clip hyphens-auto" suppressHydrationWarning>
<a
href="#conteudo"
className="sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-[200] focus:rounded-full focus:bg-ink focus:px-5 focus:py-3 focus:text-sm focus:font-semibold focus:text-canvas"
>
{messages?.Common?.skipToContent || "Pular para o conteúdo"}
</a>
<NextIntlClientProvider locale={locale} messages={messages}>
<Providers>
{children}
</Providers>
</NextIntlClientProvider>
</body>
</html>
);
}
@@ -1,3 +1,4 @@
import { notFound } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import BookCover from "@/components/BookCover";
@@ -16,19 +17,29 @@ import {
Wifi,
} from "lucide-react";
export const metadata = paginaMeta({
titulo: "Microcontroladores ESP32, o livro",
descricao:
"Conheça o livro Microcontroladores ESP32: conectividade, eficiência e desempenho. 12 partes e 78 capítulos em português sobre arquitetura, energia, rádio, periféricos e firmware.",
caminho: "/livro",
keywords: [
"livro ESP32",
"Microcontroladores ESP32",
"livro de ESP32 em português",
"Lucas Rayan Guerra",
"Ciência Embarcada",
],
});
export function generateStaticParams() {
return [{ locale: "pt" }];
}
export async function generateMetadata({ params }) {
const { locale } = await params;
if (locale !== "pt") {
return {};
}
return paginaMeta({
titulo: "Microcontroladores ESP32, o livro",
descricao:
"Conheça o livro Microcontroladores ESP32: conectividade, eficiência e desempenho. 12 partes e 78 capítulos em português sobre arquitetura, energia, rádio, periféricos e firmware.",
caminho: "/pt/livro",
keywords: [
"livro ESP32",
"Microcontroladores ESP32",
"livro de ESP32 em português",
"Lucas Rayan Guerra",
"Ciência Embarcada",
],
});
}
const CHAPTERS = [
{
@@ -128,7 +139,11 @@ const FACTS = [
["ISBN", SITE.livroIsbn],
];
export default function LivroPage() {
export default async function LivroPage({ params }) {
const { locale } = await params;
if (locale !== "pt") {
notFound();
}
return (
<div className="site-canvas min-h-screen">
<script
+118
View File
@@ -0,0 +1,118 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import Link from "next/link";
import { ArrowRight, BookOpen, Compass, Scale, SlidersHorizontal } from "lucide-react";
import { getLocale } from "next-intl/server";
import { getLocalizedHref } from "@/i18n/links";
export const metadata = {
title: "404",
robots: { index: false, follow: false },
};
const CAMINHOS_PT = [
{ href: "/series", icon: Compass, titulo: "Séries ESP32", texto: "As 12 famílias, com pinagem e especificações." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Seletor de chip", texto: "Responda a oito perguntas e receba os modelos indicados." },
{ href: "/comparacao", icon: Scale, titulo: "Comparador", texto: "Até quatro séries lado a lado." },
{ href: "/glossario", icon: BookOpen, titulo: "Glossário", texto: "Termos de hardware explicados em português." },
];
const CAMINHOS_EN = [
{ href: "/series", icon: Compass, titulo: "ESP32 Series", texto: "The 12 families, with pinouts and specifications." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Chip selector", texto: "Answer eight questions and get recommended models." },
{ href: "/comparacao", icon: Scale, titulo: "Comparator", texto: "Up to four series side by side." },
{ href: "/glossario", icon: BookOpen, titulo: "Glossary", texto: "Hardware terms explained clearly." },
];
const CAMINHOS_ES = [
{ href: "/series", icon: Compass, titulo: "Series ESP32", texto: "Las 12 familias, con patillaje y especificaciones." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Selector de chip", texto: "Responda a ocho preguntas y reciba los modelos recomendados." },
{ href: "/comparacao", icon: Scale, titulo: "Comparador", texto: "Hasta cuatro series frente a frente." },
{ href: "/glossario", icon: BookOpen, titulo: "Glosario", texto: "Términos de hardware explicados con claridad." },
];
const CAMINHOS_FR = [
{ href: "/series", icon: Compass, titulo: "Séries ESP32", texto: "Les 12 familles, avec brochage et spécifications." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Sélecteur de puce", texto: "Répondez à huit questions et obtenez les modèles recommandés." },
{ href: "/comparacao", icon: Scale, titulo: "Comparateur", texto: "Jusqu'à quatre séries côte à côte." },
{ href: "/glossario", icon: BookOpen, titulo: "Glossaire", texto: "Les termes matériels expliqués clairement." },
];
const CAMINHOS_DE = [
{ href: "/series", icon: Compass, titulo: "ESP32-Serien", texto: "Die 12 Familien mit Pinbelegung und Spezifikationen." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Chip-Auswahl", texto: "Beantworten Sie acht Fragen und erhalten Sie passende Empfehlungen." },
{ href: "/comparacao", icon: Scale, titulo: "Vergleich", texto: "Bis zu vier Serien im direkten Vergleich." },
{ href: "/glossario", icon: BookOpen, titulo: "Glossar", texto: "Hardware-Begriffe verständlich erklärt." },
];
const CAMINHOS_ZH = [
{ href: "/series", icon: Compass, titulo: "ESP32 系列", texto: "12 个系列,含引脚与规格。" },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "芯片选型", texto: "回答八个问题,获得推荐型号。" },
{ href: "/comparacao", icon: Scale, titulo: "对比工具", texto: "最多四个系列并排对比。" },
{ href: "/glossario", icon: BookOpen, titulo: "术语表", texto: "清晰解释硬件术语。" },
];
export default async function NotFound() {
let locale = "pt";
try {
locale = await getLocale();
} catch {
locale = "pt";
}
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const caminhos = isEn ? CAMINHOS_EN : isEs ? CAMINHOS_ES : isFr ? CAMINHOS_FR : isZh ? CAMINHOS_ZH : isDe ? CAMINHOS_DE : CAMINHOS_PT;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo" className="shell section">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow justify-center">{isEn ? "Error 404" : isFr ? "Erreur 404" : isZh ? "错误 404" : isDe ? "Fehler 404" : "Error 404"}</p>
<h1 className="page-title mt-4">{isEn ? "This page does not exist." : isEs ? "Esta página no existe." : isFr ? "Cette page n'existe pas." : isZh ? "该页面不存在。" : isDe ? "Diese Seite existiert nicht." : "Essa página não existe."}</h1>
<p className="lede mx-auto mt-5 max-w-xl">
{isEn
? "The address may have changed or was mistyped. Choose one of these paths to continue."
: isEs
? "La dirección puede haber cambiado o estar mal escrita. Elija uno de estos caminos para continuar."
: isFr
? "L'adresse a peut-être changé ou a été mal saisie. Choisissez l'un de ces chemins pour continuer."
: isZh ? "地址可能已更改或输入有误。请从以下入口继续浏览。" : isDe
? "Die Adresse wurde möglicherweise geändert oder falsch eingegeben. Wählen Sie einen dieser Wege, um fortzufahren."
: "O endereço pode ter mudado ou estar digitado errado. Escolha um destes caminhos para continuar."}
</p>
<div className="mt-8 flex justify-center">
<Link href={isEn ? "/en" : isEs ? "/es" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/"} className="btn btn-primary">
{isEn ? "Back to home" : isEs ? "Volver al inicio" : isFr ? "Retour à l'accueil" : isZh ? "返回首页" : isDe ? "Zur Startseite" : "Voltar ao início"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
<ul className="mx-auto mt-14 grid max-w-4xl gap-3 sm:grid-cols-2">
{caminhos.map(({ href, icon: Icon, titulo, texto }) => {
const targetHref = getLocalizedHref(href, locale);
return (
<li key={href}>
<Link href={targetHref} className="card card-interactive group flex h-full items-start gap-4 p-5">
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<span>
<span className="block font-semibold text-ink">{titulo}</span>
<span className="mt-0.5 block text-sm text-muted">{texto}</span>
</span>
</Link>
</li>
);
})}
</ul>
</main>
<Footer />
</div>
);
}
+801
View File
@@ -0,0 +1,801 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import BookCover from "@/components/BookCover";
import Link from "next/link";
import seriesDataPt from "@/public/series.json";
import frameworksDataPt from "@/public/frameworks.json";
import seriesDataEn from "@/data/en/series.json";
import frameworksDataEn from "@/data/en/frameworks.json";
import seriesDataEs from "@/data/es/series.json";
import frameworksDataEs from "@/data/es/frameworks.json";
import seriesDataFr from "@/data/fr/series.json";
import frameworksDataFr from "@/data/fr/frameworks.json";
import seriesDataDe from "@/data/de/series.json";
import seriesDataZh from "@/data/zh-CN/series.json";
import frameworksDataDe from "@/data/de/frameworks.json";
import frameworksDataZh from "@/data/zh-CN/frameworks.json";
import { SITE } from "@/lib/seo";
import { getLocalizedHref } from "@/i18n/links";
import {
AlertTriangle,
ArrowRight,
ArrowUpRight,
BookOpen,
Box,
Cpu,
Scale,
SlidersHorizontal,
Terminal,
} from "lucide-react";
const FEATURED = ["ESP32", "ESP32-S3", "ESP32-C6", "ESP32-C3", "ESP32-P4", "ESP32-H2"];
const TOOLS_PT = [
{
href: "/seletor",
title: "Seletor inteligente",
desc: "Responda oito perguntas sobre o projeto e receba os chips mais compatíveis, com justificativa técnica.",
icon: SlidersHorizontal,
action: "Encontrar meu chip",
},
{
href: "/comparacao",
title: "Comparador de séries",
desc: "Coloque até quatro modelos lado a lado e compare núcleos, rádio, memória, periféricos e segurança.",
icon: Scale,
action: "Comparar agora",
},
{
href: "/diagnostico",
title: "Diagnóstico de falhas",
desc: "Causas e correções para brownout, bootloop, Guru Meditation, watchdog e falhas de flash.",
icon: AlertTriangle,
action: "Abrir diagnóstico",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, bibliotecas e BSPs do registro oficial da Espressif, com manifesto pronto para o projeto.",
icon: Box,
action: "Explorar componentes",
},
{
href: "/frameworks",
title: "Frameworks e SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython e as ferramentas que ficam em volta do chip.",
icon: Terminal,
action: "Ver frameworks",
},
{
href: "/catalogo",
title: "Catálogo de placas",
desc: "DevKits e módulos reais, com interface USB, sensores integrados e link para a loja oficial.",
icon: Cpu,
action: "Ver placas",
},
];
const TOOLS_EN = [
{
href: "/seletor",
title: "Smart Selector",
desc: "Answer eight questions about your project and find recommended chips, backed by technical rationale.",
icon: SlidersHorizontal,
action: "Find my chip",
},
{
href: "/comparacao",
title: "Series Comparator",
desc: "Place up to four models side by side and compare cores, radio, memory, peripherals, and security.",
icon: Scale,
action: "Compare now",
},
{
href: "/diagnostico",
title: "Fault Diagnostics",
desc: "Root causes and fixes for brownout, bootloop, Guru Meditation, watchdog, and flash errors.",
icon: AlertTriangle,
action: "Open diagnostics",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, libraries and BSPs from the official Espressif registry, with ready-to-use manifests.",
icon: Box,
action: "Explore components",
},
{
href: "/frameworks",
title: "Frameworks & SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython and the tools built around the silicon.",
icon: Terminal,
action: "View frameworks",
},
{
href: "/catalogo",
title: "Board Catalog",
desc: "Real DevKits and modules, with USB interfaces, integrated sensors and direct store links.",
icon: Cpu,
action: "View boards",
},
];
const TOOLS_ES = [
{
href: "/seletor",
title: "Selector inteligente",
desc: "Responda a ocho preguntas sobre su proyecto y reciba los chips más compatibles, con justificación técnica.",
icon: SlidersHorizontal,
action: "Encontrar mi chip",
},
{
href: "/comparacao",
title: "Comparador de series",
desc: "Compare hasta cuatro modelos frente a frente: núcleos, radio, memoria, periféricos y seguridad.",
icon: Scale,
action: "Comparar ahora",
},
{
href: "/diagnostico",
title: "Diagnóstico de fallos",
desc: "Causas y soluciones para brownout, bootloop, Guru Meditation, watchdog y fallos de flash.",
icon: AlertTriangle,
action: "Abrir diagnóstico",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, bibliotecas y BSPs del registro oficial de Espressif, con manifiesto listo para su proyecto.",
icon: Box,
action: "Explorar componentes",
},
{
href: "/frameworks",
title: "Frameworks y SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython y las herramientas que rodean al silicio.",
icon: Terminal,
action: "Ver frameworks",
},
{
href: "/catalogo",
title: "Catálogo de placas",
desc: "DevKits y módulos reales, con interfaz USB, sensores integrados y enlace directo a la tienda oficial.",
icon: Cpu,
action: "Ver placas",
},
];
const TOOLS_FR = [
{
href: "/seletor",
title: "Sélecteur intelligent",
desc: "Répondez à huit questions sur votre projet et découvrez les puces recommandées, avec justification technique.",
icon: SlidersHorizontal,
action: "Trouver ma puce",
},
{
href: "/comparacao",
title: "Comparateur de séries",
desc: "Comparez jusqu'à quatre modèles côte à côte : cœurs, radio, mémoire, périphériques et sécurité.",
icon: Scale,
action: "Comparer maintenant",
},
{
href: "/diagnostico",
title: "Diagnostic de pannes",
desc: "Causes et solutions pour brownout, bootloop, Guru Meditation, watchdog et erreurs de flash.",
icon: AlertTriangle,
action: "Ouvrir le diagnostic",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Pilotes, bibliothèques et BSP du registre officiel Espressif, avec manifeste prêt pour votre projet.",
icon: Box,
action: "Explorer les composants",
},
{
href: "/frameworks",
title: "Frameworks et SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython et les outils gravitant autour de la puce.",
icon: Terminal,
action: "Voir les frameworks",
},
{
href: "/catalogo",
title: "Catalogue de cartes",
desc: "DevKits et modules réels, avec interface USB, capteurs intégrés et lien vers la boutique officielle.",
icon: Cpu,
action: "Voir les cartes",
},
];
const TOOLS_DE = [
{
href: "/seletor",
title: "Intelligente Auswahl",
desc: "Beantworten Sie acht Fragen zu Ihrem Projekt und erhalten Sie passende Chip-Empfehlungen mit technischer Begründung.",
icon: SlidersHorizontal,
action: "Meinen Chip finden",
},
{
href: "/comparacao",
title: "Serienvergleich",
desc: "Vergleichen Sie bis zu vier Modelle nebeneinander: Kerne, Funk, Speicher, Peripherie und Sicherheit.",
icon: Scale,
action: "Jetzt vergleichen",
},
{
href: "/diagnostico",
title: "Fehlerdiagnose",
desc: "Ursachen und Lösungen für Brownout, Bootloops, Guru Meditation, Watchdog und Flash-Fehler.",
icon: AlertTriangle,
action: "Diagnose öffnen",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Treiber, Bibliotheken und BSPs aus der offiziellen Espressif-Registry, mit fertigem Manifest für Ihr Projekt.",
icon: Box,
action: "Komponenten erkunden",
},
{
href: "/frameworks",
title: "Frameworks & SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython und die Werkzeuge rund um den Chip.",
icon: Terminal,
action: "Frameworks ansehen",
},
{
href: "/catalogo",
title: "Board-Katalog",
desc: "Reale DevKits und Module, mit USB-Schnittstelle, integrierten Sensoren und Link zum offiziellen Shop.",
icon: Cpu,
action: "Boards ansehen",
},
];
const TOOLS_ZH = [
{
href: "/seletor",
title: "智能选型",
desc: "回答八个关于项目的问题,获得推荐芯片及其技术依据。",
icon: SlidersHorizontal,
action: "找到我的芯片",
},
{
href: "/comparacao",
title: "系列对比",
desc: "最多把四个型号并排放在一起,对比内核、无线、内存、外设和安全。",
icon: Scale,
action: "立即对比",
},
{
href: "/diagnostico",
title: "故障诊断",
desc: "针对欠压、启动循环、Guru Meditation、看门狗和闪存错误的根因与解决办法。",
icon: AlertTriangle,
action: "打开诊断",
},
{
href: "/componentes",
title: "Component Registry",
desc: "来自乐鑫官方注册中心的驱动、库和 BSP,附带可直接使用的清单。",
icon: Box,
action: "探索组件",
},
{
href: "/frameworks",
title: "框架与 SDK",
desc: "ESP-IDF、Arduino、Rust、Matter、MicroPython,以及围绕芯片构建的工具。",
icon: Terminal,
action: "查看框架",
},
{
href: "/catalogo",
title: "开发板目录",
desc: "真实的 DevKit 与模组,含 USB 接口、板载传感器和直达商店的链接。",
icon: Cpu,
action: "查看开发板",
},
];
const ERRORS_PT = [
{
code: "Brownout detector was triggered",
cause: "Queda de tensão na inicialização do rádio.",
fix: "Capacitor de 10–100 µF junto ao chip e fonte de 5 V com corrente suficiente.",
},
{
code: "Guru Meditation Error",
cause: "Ponteiro inválido, stack overflow ou uso incorreto de interrupção.",
fix: "Leia o backtrace com addr2line e dimensione a stack da task no FreeRTOS.",
},
{
code: "ADC2 indisponível com Wi-Fi",
cause: "O controlador de rádio reserva o ADC2 enquanto está ativo.",
fix: "Use os pinos do ADC1 para sensores analógicos que convivem com o Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tensão ou modo de flash incorretos, ou pino de strapping preso no boot.",
fix: "Confira 3,3 V, pull-ups de boot e a configuração de flash no esptool.",
},
];
const ERRORS_EN = [
{
code: "Brownout detector was triggered",
cause: "Voltage sag upon radio startup.",
fix: "10–100 µF capacitor close to chip and a 5 V supply with sufficient current.",
},
{
code: "Guru Meditation Error",
cause: "Invalid pointer, stack overflow, or improper ISR usage.",
fix: "Inspect backtrace with addr2line and properly size FreeRTOS task stacks.",
},
{
code: "ADC2 unavailable with Wi-Fi",
cause: "Internal radio controller reserves ADC2 while active.",
fix: "Use ADC1 pins for analog sensors operating alongside Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Incorrect flash voltage/mode or strapping pin pulled during boot.",
fix: "Check 3.3 V rail, boot pull-ups, and flash configuration in esptool.",
},
];
const ERRORS_ES = [
{
code: "Brownout detector was triggered",
cause: "Caída de tensión al inicializar la etapa de radio.",
fix: "Condensador de 10–100 µF junto al chip y fuente de 5 V con corriente suficiente.",
},
{
code: "Guru Meditation Error",
cause: "Puntero inválido, desbordamiento de pila o uso incorrecto de interrupciones.",
fix: "Analice el backtrace con addr2line y dimensione la pila de la tarea en FreeRTOS.",
},
{
code: "ADC2 no disponible con Wi-Fi",
cause: "El controlador de radio reserva ADC2 mientras permanece activo.",
fix: "Utilice los pines de ADC1 para sensores analógicos que funcionen junto con Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tensión o modo de flash incorrectos, o pin de strapping forzado en el arranque.",
fix: "Compruebe la línea de 3,3 V, los pull-ups de arranque y la configuración de flash en esptool.",
},
];
const ERRORS_FR = [
{
code: "Brownout detector was triggered",
cause: "Baisse de tension lors du démarrage de la radio.",
fix: "Condensateur de 10 à 100 µF au plus près de la puce et alimentation 5 V avec courant suffisant.",
},
{
code: "Guru Meditation Error",
cause: "Pointeur invalide, dépassement de pile ou mauvaise utilisation des interruptions.",
fix: "Analysez le backtrace avec addr2line et dimensionnez la pile de la tâche sous FreeRTOS.",
},
{
code: "ADC2 indisponible avec le Wi-Fi",
cause: "Le contrôleur radio réserve l'ADC2 tant qu'il est actif.",
fix: "Utilisez les broches de l'ADC1 pour les capteurs analogiques fonctionnant conjointement avec le Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tension ou mode de flash incorrect, ou broche de strapping forcée au démarrage.",
fix: "Vérifiez la ligne 3,3 V, les pull-ups de démarrage et la configuration de flash dans esptool.",
},
];
const ERRORS_DE = [
{
code: "Brownout detector was triggered",
cause: "Spannungseinbruch beim Starten der Funkeinheit.",
fix: "Kondensator mit 10–100 µF nah am Chip und 5-V-Netzteil mit ausreichender Stromstärke.",
},
{
code: "Guru Meditation Error",
cause: "Ungültiger Zeiger, Stack-Überlauf oder fehlerhafte Interrupt-Nutzung.",
fix: "Backtrace mit addr2line analysieren und Stack-Größe der FreeRTOS-Task anpassen.",
},
{
code: "ADC2 nicht verfügbar bei aktivem Wi-Fi",
cause: "Der Funk-Controller reserviert ADC2, solange er aktiv ist.",
fix: "Nutzen Sie ADC1-Pins für analoge Sensoren, die gleichzeitig mit Wi-Fi betrieben werden.",
},
{
code: "Flash Read err / bootloader",
cause: "Falsche Flash-Spannung/-Modus oder beim Booten falsch beschalteter Strapping-Pin.",
fix: "3,3-V-Schiene, Boot-Pull-ups und Flash-Konfiguration in esptool überprüfen.",
},
];
const ERRORS_ZH = [
{
code: "Brownout detector was triggered",
cause: "射频启动时电压跌落。",
fix: "在芯片附近加 10–100 µF 电容,并使用电流足够的 5 V 电源。",
},
{
code: "Guru Meditation Error",
cause: "无效指针、栈溢出,或 ISR 使用不当。",
fix: "用 addr2line 查看回溯信息,并合理设置 FreeRTOS 任务的栈大小。",
},
{
code: "Wi-Fi 开启时 ADC2 不可用",
cause: "射频控制器工作时会占用 ADC2。",
fix: "与 Wi-Fi 同时使用模拟传感器时,请用 ADC1 引脚。",
},
{
code: "Flash Read err / bootloader",
cause: "闪存电压/模式不正确,或启动时启动配置引脚被拉到错误电平。",
fix: "检查 3.3 V 电源轨、启动上拉,以及 esptool 中的闪存配置。",
},
];
export default async function Home({ params }) {
const { locale } = await params;
const isPt = locale === "pt";
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const getLinkHref = (href) => getLocalizedHref(`/${locale}${href}`, locale);
const seriesData = isPt ? seriesDataPt : isEs ? seriesDataEs : isFr ? seriesDataFr : isZh ? seriesDataZh : isDe ? seriesDataDe : seriesDataEn;
const frameworksData = isPt ? frameworksDataPt : isEs ? frameworksDataEs : isFr ? frameworksDataFr : isZh ? frameworksDataZh : isDe ? frameworksDataDe : frameworksDataEn;
const tools = isPt ? TOOLS_PT : isEs ? TOOLS_ES : isFr ? TOOLS_FR : isZh ? TOOLS_ZH : isDe ? TOOLS_DE : TOOLS_EN;
const errors = isPt ? ERRORS_PT : isEs ? ERRORS_ES : isFr ? ERRORS_FR : isZh ? ERRORS_ZH : isDe ? ERRORS_DE : ERRORS_EN;
const seriesCount = Object.keys(seriesData).length;
const frameworkCount = Object.keys(frameworksData).length;
const featured = FEATURED.map((key) => [key, seriesData[key]]).filter(([, serie]) => Boolean(serie));
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<section className="shell pb-10 pt-14 sm:pt-20 lg:pb-14 lg:pt-24">
<div className="mx-auto max-w-4xl text-center">
<span className="chip chip-accent">
<Cpu className="h-3.5 w-3.5" aria-hidden="true" />
{isPt ? "Documentação aberta do ESP32" : isEs ? "Documentación abierta de ESP32" : isFr ? "Documentation ouverte de l'ESP32" : isZh ? "ESP32 开放文档" : isDe ? "Offene ESP32-Dokumentation" : "Open ESP32 documentation"}
</span>
<h1 className="display mt-6 text-[clamp(2.9rem,7.4vw,5.4rem)]">
{isPt ? (
<>
O ESP32,
<br className="sm:hidden" /> sem ruído.
</>
) : isEs ? (
<>
El ESP32,
<br className="sm:hidden" /> sin ruido.
</>
) : isFr ? (
<>
L'ESP32,
<br className="sm:hidden" /> sans bruit.
</>
) : isZh ? ( <>
ESP32,<br className="sm:hidden" />去繁就简。
</> ) : isDe ? (
<>
Der ESP32,
<br className="sm:hidden" /> ohne Umwege.
</>
) : (
<>
The ESP32,
<br className="sm:hidden" /> without noise.
</>
)}
</h1>
<p className="lede mx-auto mt-6 max-w-2xl">
{isPt
? "Especificações, pinagem, comparações e diagnóstico em uma leitura só. Menos tradução de datasheet, mais tempo com o protótipo na bancada."
: isEs
? "Especificaciones, patillaje, comparaciones y diagnóstico en una sola lectura. Menos traducción de hojas de datos, más tiempo con el prototipo en el banco de trabajo."
: isFr
? "Spécifications, brochage, comparaisons et diagnostics en une seule lecture. Moins de traduction de fiches techniques, plus de temps à l'établi."
: isZh ? "规格、引脚、对比与故障诊断,一次读完。少啃数据手册,多花时间在工作台上做原型。" : isDe
? "Spezifikationen, Pinbelegung, Vergleiche und Diagnose auf einen Blick. Weniger Datenblatt-Übersetzung, mehr Zeit am Prüfplatz."
: "Specifications, pinouts, comparisons and diagnostics in a single read. Less datasheet translation, more workbench time."}
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href={getLinkHref("/seletor")} className="btn btn-primary w-full sm:w-auto">
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
{isPt ? "Escolher meu chip" : isEs ? "Elegir mi chip" : isFr ? "Choisir ma puce" : isZh ? "选择我的芯片" : isDe ? "Meinen Chip wählen" : "Choose my chip"}
</Link>
<Link href={getLinkHref("/series")} className="btn btn-ghost w-full sm:w-auto">
{isPt ? (
<>Explorar as {seriesCount} séries</>
) : isEs ? (
<>Explorar las {seriesCount} series</>
) : isFr ? (
<>Explorer les {seriesCount} séries</>
) : isZh ? ( <>浏览全部 {seriesCount} 个系列</> ) : isDe ? (
<>Die {seriesCount} Serien erkunden</>
) : (
<>Explore the {seriesCount} series</>
)}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<p className="mt-7 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-sm text-muted">
<span><strong className="font-semibold text-ink">{seriesCount}</strong> {isPt ? "séries" : isEs ? "series" : isFr ? "séries" : isZh ? "个系列" : isDe ? "Serien" : "series"}</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">{frameworkCount}</strong> {isZh ? "个框架" : isDe ? "Frameworks" : "frameworks"}</span>
{isPt ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">78</strong> capítulos no livro</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% em português</span>
</>
) : isEs ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% en español</span>
</>
) : isFr ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100 % en français</span>
</>
) : isZh ? ( <>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% 中文</span>
</> ) : isDe ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100 % auf Deutsch</span>
</>
) : (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% in English</span>
</>
)}
</p>
</div>
<div className="panel mt-12 overflow-hidden sm:mt-16">
<div className="flex flex-wrap items-center justify-between gap-3 px-5 py-4 sm:px-7">
<div>
<h2 className="text-sm font-semibold text-ink">{isPt ? "Séries em destaque" : isEs ? "Series destacadas" : isFr ? "Séries en vedette" : isZh ? "精选系列" : isDe ? "Vorgestellte Serien" : "Featured series"}</h2>
<p className="mt-0.5 text-xs text-muted">
{isPt ? "O essencial de cada família, antes de abrir o datasheet." : isEs ? "Lo esencial de cada familia, antes de abrir la hoja de datos." : isFr ? "L'essentiel de chaque famille, avant d'ouvrir la fiche technique." : isZh ? "打开数据手册之前,先看每个系列的要点。" : isDe ? "Das Wesentliche jeder Familie, bevor Sie das Datenblatt öffnen." : "The essentials of each family before opening the datasheet."}
</p>
</div>
<Link href={getLinkHref("/series")} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent transition-colors hover:text-accent-strong">
{isPt ? "Índice completo" : isEs ? "Índice completo" : isFr ? "Index complet" : isZh ? "完整索引" : isDe ? "Vollständiger Index" : "Full index"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<div className="grid gap-px border-t border-line bg-line sm:grid-cols-2 lg:grid-cols-3">
{featured.map(([key, serie]) => (
<Link
key={key}
href={getLinkHref(`/series/${key}`)}
className="group flex min-w-0 flex-col bg-surface p-5 transition-colors duration-300 hover:bg-surface-2 sm:p-6"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h3 className="font-display text-xl font-semibold tracking-[-0.035em] text-ink">{key}</h3>
<p className="mt-1 truncate text-xs text-muted">{serie.arquitetura}</p>
</div>
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-full bg-accent-soft text-accent transition-transform duration-300 group-hover:scale-105">
<Cpu className="h-4 w-4" aria-hidden="true" />
</span>
</div>
<p className="mt-5 line-clamp-2 text-sm leading-relaxed text-muted">{serie.descricao}</p>
<div className="mt-5 flex items-center justify-between gap-3 border-t border-line pt-3.5">
<span className="truncate font-mono text-[0.6875rem] text-ink-soft">{serie.frequencia}</span>
<span className="inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent">
{isPt ? "Ficha" : isEs ? "Ficha" : isFr ? "Fiche" : isZh ? "规格表" : isDe ? "Datenblatt" : "Spec sheet"}
<ArrowUpRight className="h-3.5 w-3.5 transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</div>
</Link>
))}
</div>
</div>
</section>
{isPt && (
<section className="shell section pt-8 sm:pt-12" aria-labelledby="livro-titulo">
<div className="relative isolate overflow-hidden rounded-[2rem] bg-[#0b0d10] ring-1 ring-white/10 dark:bg-[#05070a] dark:ring-white/15 sm:rounded-[2.5rem]">
<div
className="pointer-events-none absolute -left-24 top-1/2 -z-10 h-80 w-80 -translate-y-1/2 rounded-full bg-[#2dd4bf]/15 blur-3xl"
aria-hidden="true"
/>
<div className="grid lg:grid-cols-[0.82fr_1.18fr]">
<div className="order-1 flex flex-col justify-center p-7 sm:p-10 lg:order-2 lg:p-14">
<span className="inline-flex w-fit items-center gap-2 rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold text-[#75cdc1]">
<BookOpen className="h-3.5 w-3.5" aria-hidden="true" />
Livro novo
</span>
<h2 id="livro-titulo" className="mt-5 font-display text-[clamp(2rem,4.2vw,3.2rem)] font-semibold leading-[1.05] tracking-[-0.04em] text-[#f4f6f8]">
{SITE.livroTitulo}
</h2>
<p className="mt-2 text-base text-[#a6afbd]">{SITE.livroSubtitulo}</p>
<p className="mt-5 max-w-xl text-sm leading-relaxed text-[#c4cbd5]">
Um percurso completo pelo hardware e pelo firmware do ESP32: da arquitetura do chip
à implantação de produtos conectados. São 12 partes e 78 capítulos sobre Arduino,
ESP-IDF, FreeRTOS, Wi-Fi, BLE, Thread e Matter, periféricos, depuração, baixo consumo
e segurança.
</p>
<p className="mt-6 flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-[#a6afbd]">
<span>12 partes</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>78 capítulos</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>ISBN {SITE.livroIsbn}</span>
</p>
<div className="mt-7 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
<a
href={SITE.livroAmazon}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full bg-[#2dd4bf] px-5 text-sm font-semibold text-[#06201d] transition-colors duration-300 hover:bg-[#5eead4]"
>
Comprar digital
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<a
href={SITE.livroUiclap}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full border border-white/20 px-5 text-sm font-semibold text-[#f4f6f8] transition-colors duration-300 hover:border-white/40 hover:bg-white/5"
>
Comprar impresso
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<Link href="/pt/livro" className="inline-flex min-h-11 items-center justify-center gap-1.5 rounded-full px-3 text-sm font-medium text-[#a6afbd] transition-colors duration-300 hover:text-[#f4f6f8]">
Ficha completa
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
<div className="order-2 flex items-center justify-center border-t border-white/10 p-8 sm:p-12 lg:order-1 lg:border-r lg:border-t-0 lg:p-14">
<div className="relative w-[min(15.5rem,68%)] lg:w-[min(17rem,100%)]">
<div className="absolute -inset-10 -z-10 rounded-full bg-[#2dd4bf]/10 blur-3xl" aria-hidden="true" />
<BookCover />
</div>
</div>
</div>
</div>
</section>
)}
<section className="shell section" aria-labelledby="ferramentas-titulo">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow">{isPt ? "Ferramentas" : isEs ? "Herramientas" : isFr ? "Outils" : isZh ? "工具" : isDe ? "Werkzeuge" : "Tools"}</p>
<h2 id="ferramentas-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
{isPt ? "Comece pelo problema." : isEs ? "Empiece por el problema." : isFr ? "Commencez par le problème." : isZh ? "从问题出发。" : isDe ? "Beginnen Sie beim Problem." : "Start with the problem."}
</h2>
<p className="lede mt-4">
{isPt
? "Cada ferramenta resolve uma etapa concreta do projeto, sem cadastro e sem rodeio."
: isEs
? "Cada herramienta resuelve una fase concreta del proyecto, sin registros ni rodeos."
: isFr
? "Chaque outil répond à une étape concrète du projet, sans inscription ni détour."
: isZh ? "每个工具对应开发中的一个具体阶段,无需注册,没有废话。" : isDe
? "Jedes Werkzeug löst einen konkreten Projektschritt – ohne Registrierung und ohne Umwege."
: "Each tool addresses a concrete development phase, with no sign-ups and zero fluff."}
</p>
</div>
<div className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{tools.map((tool) => {
const Icon = tool.icon;
return (
<Link key={tool.href} href={getLinkHref(tool.href)} className="card card-interactive group flex flex-col p-5 sm:p-6">
<span className="grid h-11 w-11 place-items-center rounded-2xl bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<h3 className="mt-5 font-display text-lg font-semibold tracking-[-0.025em] text-ink">{tool.title}</h3>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{tool.desc}</p>
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-accent">
{tool.action}
<ArrowRight className="h-4 w-4 transition-transform duration-300 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
);
})}
</div>
</section>
<section className="shell section pt-0" aria-labelledby="diagnostico-titulo">
<div className="grid items-start gap-10 lg:grid-cols-[0.78fr_1.22fr] lg:gap-16">
<div className="lg:sticky lg:top-28">
<p className="eyebrow">{isPt ? "Diagnóstico" : isEs ? "Diagnóstico" : isFr ? "Diagnostic" : isZh ? "故障诊断" : isDe ? "Diagnose" : "Diagnostics"}</p>
<h2 id="diagnostico-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
{isPt ? "O primeiro boot não precisa virar noite." : isEs ? "El primer arranque no tiene por qué desvelarlo." : isFr ? "Le premier démarrage n'a pas à vous gâcher la nuit." : isZh ? "第一次启动,不必折腾一整晚。" : isDe ? "Der erste Boot muss nicht die Nacht kosten." : "First boot doesn't have to take all night."}
</h2>
<p className="lede mt-4">
{isPt
? "Os erros mais comuns têm causa conhecida. O guia parte da mensagem no terminal e chega ao ajuste de hardware ou firmware."
: isEs
? "Los errores más comunes tienen una causa conocida. Esta guía parte del mensaje en el terminal y llega al ajuste de hardware o firmware."
: isFr
? "Les erreurs les plus courantes ont une cause connue. Ce guide part du message dans le terminal pour arriver au réglage matériel ou logiciel."
: isZh ? "常见错误都有已知的原因。本指南从串口终端日志出发,引导你找到硬件或固件上的调整办法。" : isDe
? "Die häufigsten Fehler haben bekannte Ursachen. Dieser Leitfaden geht von der Terminalmeldung aus und führt zur passenden Hardware- oder Firmware-Anpassung."
: "Common errors have known causes. This guide starts with the serial terminal log and leads to the hardware or firmware adjustment."}
</p>
<Link href={getLinkHref("/diagnostico")} className="btn btn-accent mt-7">
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
{isPt ? "Abrir os 30+ diagnósticos" : isEs ? "Abrir los 30+ diagnósticos" : isFr ? "Ouvrir les 30+ diagnostics" : isZh ? "查看 30 多项诊断" : isDe ? "Die 30+ Diagnosen öffnen" : "Open the 30+ diagnostics"}
</Link>
</div>
<div className="panel-dark min-w-0 overflow-hidden rounded-[1.75rem]">
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-white/10 px-5 py-4 sm:px-6">
<span className="inline-flex items-center gap-2 font-mono text-xs text-[#75cdc1]">
<Terminal className="h-4 w-4" aria-hidden="true" />
boot.log
</span>
<span className="text-xs text-[#a6afbd]">{isPt ? "4 exemplos de 30+" : isEs ? "4 ejemplos de 30+" : isFr ? "4 exemples sur 30+" : isZh ? "30 多项中的 4 个示例" : isDe ? "4 Beispiele von 30+" : "4 examples of 30+"}</span>
</div>
<div className="divide-y divide-white/10">
{errors.map((item) => (
<Link key={item.code} href={getLinkHref("/diagnostico")} className="group grid gap-2 px-5 py-5 transition-colors duration-300 hover:bg-white/[0.035] sm:px-6">
<span className="break-words font-mono text-[0.75rem] font-medium leading-relaxed text-[#ffb39b]">{item.code}</span>
<span className="text-sm font-medium text-[#f4f6f8]">{item.cause}</span>
<span className="text-xs leading-relaxed text-[#a6afbd]">{item.fix}</span>
</Link>
))}
</div>
</div>
</div>
</section>
<section className="shell pb-20 pt-4 md:pb-28">
<div className="mx-auto max-w-3xl text-center">
<p className="eyebrow">{isPt ? "Curadoria independente" : isEs ? "Curaduría independiente" : isFr ? "Sélection indépendante" : isZh ? "独立整理" : isDe ? "Unabhängige Kuration" : "Independent curation"}</p>
<h2 className="display mt-4 text-[clamp(2rem,4.5vw,3.2rem)]">
{isPt ? "Feito para consultar no meio do projeto." : isEs ? "Diseñado para consultar en mitad del proyecto." : isFr ? "Conçu pour être consulté en plein projet." : isZh ? "为项目途中的快速查阅而做。" : isDe ? "Gemacht für das Nachschlagen mitten im Projekt." : "Built for quick lookup mid-project."}
</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
{isPt
? "O ESPDocs organiza dados públicos da Espressif e aponta sempre para a fonte oficial. Para decisões críticas, o datasheet e o Technical Reference Manual continuam sendo a palavra final."
: isEs
? "ESPDocs organiza datos públicos de Espressif y apunta siempre a la fuente oficial. Para decisiones críticas, la hoja de datos y el Technical Reference Manual continúan teniendo la última palabra."
: isFr
? "ESPDocs organise les données publiques d'Espressif et renvoie systématiquement vers la source officielle. Pour les décisions critiques, la fiche technique et le Technical Reference Manual restent la référence définitive."
: isZh ? "ESPDocs 整理乐鑫的公开数据,并直接指向官方资料来源。对于关键的工程决策,数据手册和技术参考手册仍是最终依据。" : isDe
? "ESPDocs strukturiert öffentliche Espressif-Daten und verweist stets auf die offizielle Quelle. Für kritische Entscheidungen bleiben das Datenblatt und das Technical Reference Manual maßgeblich."
: "ESPDocs organizes public Espressif data and points directly to official sources. For critical engineering decisions, the datasheet and Technical Reference Manual remain the definitive authority."}
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href={getLinkHref("/glossario")} className="btn btn-ghost w-full sm:w-auto">
<BookOpen className="h-4 w-4" aria-hidden="true" />
{isPt ? "Glossário" : isEs ? "Glosario" : isFr ? "Glossaire" : isZh ? "术语表" : isDe ? "Glossar" : "Glossary"}
</Link>
<Link href={getLinkHref("/sobre")} className="btn btn-primary w-full sm:w-auto">
{isPt ? "Sobre o projeto" : isEs ? "Acerca del proyecto" : isFr ? "À propos du projet" : isZh ? "关于本项目" : isDe ? "Über das Projekt" : "About the project"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
+246
View File
@@ -0,0 +1,246 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isZh ? "该选哪款 ESP32" : isDe
? "Welchen ESP32 wählen"
: isFr
? "Quel ESP32 choisir"
: isEs
? "Qué ESP32 elegir"
: isEn
? "Which ESP32 to Choose"
: "Qual ESP32 escolher",
descricao: isZh ? "回答几个关于连接(Wi-Fi 6、5GHz、Matter)、功耗、外设和安全的简单问题,或使用参数筛选器,找到最合适的 ESP32。" : isDe
? "Beantworten Sie einfache Fragen zu Konnektivität (Wi-Fi 6, 5 GHz, Matter), Energie, Peripherie und Sicherheit oder nutzen Sie den parametrischen Filter, um den perfekten ESP32 zu finden."
: isFr
? "Répondez à des questions simples sur la connectivité (Wi-Fi 6, 5 GHz, Matter), l'énergie, les périphériques et la sécurité ou utilisez le filtre paramétrique pour trouver l'ESP32 parfait."
: isEs
? "Responda a preguntas sencillas sobre conectividad (Wi-Fi 6, 5GHz, Matter), energía, periféricos y seguridad o use el filtro paramétrico para encontrar el ESP32 perfecto."
: isEn
? "Answer simple questions about connectivity (Wi-Fi 6, 5GHz, Matter), power, peripherals, and security or use the parametric filter to find the perfect ESP32."
: "Responda a perguntas simples sobre conectividade (Wi-Fi 6, 5GHz, Matter), energia, periféricos e segurança ou use o filtro paramétrico para encontrar o ESP32 perfeito.",
caminho: "/seletor",
locale,
keywords: isZh ? ["该选哪款 ESP32", "该用哪款 ESP32", "微控制器选型", "适合我项目的 ESP32", "ESP32 对比"] : isDe
? ["welchen ESP32 wählen", "welchen ESP32 verwenden", "Mikrocontroller auswählen", "ESP32 für mein Projekt", "ESP32 vergleichen"]
: isFr
? ["quel ESP32 choisir", "quel ESP32 utiliser", "choisir microcontrôleur", "ESP32 pour mon projet", "comparer ESP32"]
: isEs
? ["qué ESP32 elegir", "cuál ESP32 usar", "elegir microcontrolador", "ESP32 para mi proyecto", "comparar ESP32"]
: isEn
? ["which ESP32 to choose", "which ESP32 to use", "choose microcontroller", "ESP32 for my project", "compare ESP32"]
: ["qual ESP32 escolher", "qual ESP32 usar", "escolher microcontrolador", "ESP32 para meu projeto", "comparar ESP32"],
});
}
const faqsPt = [
{
pergunta: "Qual ESP32 escolher para iniciantes?",
resposta: "Para quem está começando no mundo Maker e IoT, o ESP32 clássico (NodeMCU/DevKitC) ou o ESP32-C3 são as melhores opções devido à vasta quantidade de bibliotecas, exemplos prontos no Arduino IDE e farta documentação em português.",
},
{
pergunta: "Qual ESP32 tem suporte a Wi-Fi 6, Bluetooth 6 e Thread/Zigbee/Matter?",
resposta: "O ESP32-C6 e o ESP32-C5 são as melhores séries para redes modernas. O ESP32-C6 oferece Wi-Fi 6 (2.4 GHz) e rádio 802.15.4 (Zigbee 3.0 / Thread / Matter). Já o ESP32-C5 é o primeiro a oferecer suporte a Wi-Fi 6 Dual-Band operando em 2.4 GHz e 5 GHz simultaneamente.",
},
{
pergunta: "Qual o ESP32 mais potente para Inteligência Artificial (TinyML) e Displays?",
resposta: "O ESP32-P4 (dual-core RISC-V a 400 MHz com extensões vetoriais de IA, interfaces MIPI-CSI/DSI para câmeras/telas e até 64 MB de PSRAM) e o ESP32-S3 (dual-core Xtensa a 240 MHz com aceleradores vetoriais para redes neurais e telas LCD RGB) são os mais velozes para IA na borda e interfaces gráficas ricas.",
},
{
pergunta: "Qual ESP32 consome menos energia para projetos a bateria?",
resposta: "Microcontroladores com arquitetura RISC-V compacta e coprocessador ULP, como o ESP32-C2, ESP32-C3 e ESP32-H2 (focado em 802.15.4 sem rádio Wi-Fi), oferecem correntes de deep sleep extremamente baixas (na faixa de 5 µA a 10 µA).",
},
];
const faqsEn = [
{
pergunta: "Which ESP32 to choose for beginners?",
resposta: "For makers and developers starting out in IoT, the classic ESP32 (NodeMCU/DevKitC) or ESP32-C3 are top choices thanks to extensive library support, readily available Arduino IDE examples, and thorough documentation.",
},
{
pergunta: "Which ESP32 supports Wi-Fi 6, Bluetooth 6 and Thread/Zigbee/Matter?",
resposta: "The ESP32-C6 and ESP32-C5 are the leading series for modern networking. The ESP32-C6 offers 2.4 GHz Wi-Fi 6 and 802.15.4 radio (Zigbee 3.0 / Thread / Matter). The ESP32-C5 is the first to introduce Dual-Band Wi-Fi 6 on both 2.4 GHz and 5 GHz bands simultaneously.",
},
{
pergunta: "Which is the most powerful ESP32 for AI (TinyML) and Displays?",
resposta: "The ESP32-P4 (dual-core RISC-V at 400 MHz with AI vector extensions, MIPI-CSI/DSI interfaces, and up to 64 MB PSRAM) and ESP32-S3 (dual-core Xtensa at 240 MHz with neural network vector acceleration and RGB LCD support) provide maximum speed for edge AI and rich graphical interfaces.",
},
{
pergunta: "Which ESP32 consumes the least power for battery-operated projects?",
resposta: "Compact RISC-V microcontrollers with ULP coprocessors like the ESP32-C2, ESP32-C3, and ESP32-H2 (dedicated 802.15.4 without Wi-Fi) achieve ultra-low deep sleep currents ranging between 5 µA and 10 µA.",
},
];
const faqsEs = [
{
pergunta: "¿Cuál ESP32 elegir para principiantes?",
resposta: "Para quienes se inician en el mundo Maker e IoT, el ESP32 clásico (NodeMCU/DevKitC) o el ESP32-C3 son las mejores opciones gracias al amplio soporte de bibliotecas, ejemplos listos en Arduino IDE y abundante documentación.",
},
{
pergunta: "¿Cuál ESP32 soporta Wi-Fi 6, Bluetooth 6 y Thread/Zigbee/Matter?",
resposta: "El ESP32-C6 y el ESP32-C5 son las series destacadas para redes modernas. El ESP32-C6 ofrece Wi-Fi 6 (2.4 GHz) y radio 802.15.4 (Zigbee 3.0 / Thread / Matter). El ESP32-C5 es el primero en ofrecer soporte para Wi-Fi 6 de doble banda operando en 2.4 GHz y 5 GHz simultáneamente.",
},
{
pergunta: "¿Cuál es el ESP32 más potente para Inteligencia Artificial (TinyML) y Pantallas?",
resposta: "El ESP32-P4 (dual-core RISC-V a 400 MHz con extensiones vectoriales de IA, interfaces MIPI-CSI/DSI para cámaras/pantallas y hasta 64 MB de PSRAM) y el ESP32-S3 (dual-core Xtensa a 240 MHz con aceleradores vectoriales para redes neuronales y soporte para LCD RGB) son los más rápidos para IA en el borde e interfaces gráficas avanzadas.",
},
{
pergunta: "¿Cuál ESP32 consume menos energía para proyectos a batería?",
resposta: "Los microcontroladores con arquitectura RISC-V compacta y coprocesador ULP, como el ESP32-C2, ESP32-C3 y ESP32-H2 (dedicado a 802.15.4 sin radio Wi-Fi), ofrecen corrientes de deep sleep extremadamente bajas (en el rango de 5 µA a 10 µA).",
},
];
const faqsFr = [
{
pergunta: "Quel ESP32 choisir pour débuter ?",
resposta: "Pour débuter dans le monde Maker et l'IoT, l'ESP32 classique (NodeMCU/DevKitC) ou l'ESP32-C3 sont les meilleurs choix grâce au vaste support de bibliothèques, aux exemples prêts à l'emploi dans l'IDE Arduino et à une documentation abondante.",
},
{
pergunta: "Quel ESP32 prend en charge le Wi-Fi 6, le Bluetooth 6 et Thread/Zigbee/Matter ?",
resposta: "L'ESP32-C6 et l'ESP32-C5 sont les séries phares pour les réseaux modernes. L'ESP32-C6 offre le Wi-Fi 6 (2,4 GHz) et une radio 802.15.4 (Zigbee 3.0 / Thread / Matter). L'ESP32-C5 est le premier à offrir la prise en charge du Wi-Fi 6 bi-bande fonctionnant simultanément en 2,4 GHz et 5 GHz.",
},
{
pergunta: "Quel est l'ESP32 le plus puissant pour l'Intelligence Artificielle (TinyML) et les écrans ?",
resposta: "L'ESP32-P4 (dual-core RISC-V à 400 MHz avec extensions vectorielles IA, interfaces MIPI-CSI/DSI pour caméras/écrans et jusqu'à 64 Mo de PSRAM) et l'ESP32-S3 (dual-core Xtensa à 240 MHz avec accélérateurs vectoriels pour réseaux neuronaux et écrans LCD RGB) sont les plus rapides pour l'IA en périphérie et les interfaces graphiques riches.",
},
{
pergunta: "Quel ESP32 consomme le moins d'énergie pour les projets sur batterie ?",
resposta: "Les microcontrôleurs à architecture RISC-V compacte avec coprocesseur ULP, comme l'ESP32-C2, l'ESP32-C3 et l'ESP32-H2 (dédié au 802.15.4 sans radio Wi-Fi), offrent des courants de deep sleep extrêmement faibles (de l'ordre de 5 µA à 10 µA).",
},
];
const faqsDe = [
{
pergunta: "Welchen ESP32 sollten Einsteiger wählen?",
resposta: "Für Einsteiger in die Maker- und IoT-Welt sind der klassische ESP32 (NodeMCU/DevKitC) oder der ESP32-C3 die beste Wahl, dank breiter Bibliotheksunterstützung, zahlreicher fertiger Beispiele in der Arduino IDE und umfassender Dokumentation.",
},
{
pergunta: "Welcher ESP32 unterstützt Wi-Fi 6, Bluetooth 6 und Thread/Zigbee/Matter?",
resposta: "Der ESP32-C6 und der ESP32-C5 sind die führenden Serien für moderne Netzwerke. Der ESP32-C6 bietet Wi-Fi 6 (2,4 GHz) und ein 802.15.4-Funkmodul (Zigbee 3.0 / Thread / Matter). Der ESP32-C5 bietet als erster Dual-Band Wi-Fi 6 mit simultanem Betrieb auf 2,4 GHz und 5 GHz.",
},
{
pergunta: "Welcher ESP32 ist am leistungsfähigsten für Künstliche Intelligenz (TinyML) und Displays?",
resposta: "Der ESP32-P4 (Dual-Core RISC-V mit 400 MHz, KI-Vektorerweiterungen, MIPI-CSI/DSI-Schnittstellen für Kameras/Displays und bis zu 64 MB PSRAM) und der ESP32-S3 (Dual-Core Xtensa mit 240 MHz, Vektorbeschleunigern für neuronale Netze und RGB-LCD-Unterstützung) sind am schnellsten für Edge-KI und anspruchsvolle grafische Benutzeroberflächen.",
},
{
pergunta: "Welcher ESP32 verbraucht am wenigsten Energie für batteriebetriebene Projekte?",
resposta: "Kompakte RISC-V-Mikrocontroller mit ULP-Coprozessor wie der ESP32-C2, ESP32-C3 und ESP32-H2 (dediziert für 802.15.4 ohne Wi-Fi-Funk) bieten extrem niedrige Deep-Sleep-Ströme im Bereich von 5 µA bis 10 µA.",
},
];
const faqsZh = [
{
pergunta: "新手该选哪款 ESP32?",
resposta: "对刚入门物联网的创客和开发者来说,经典 ESP32(NodeMCU/DevKitC)或 ESP32-C3 是首选:库支持丰富,Arduino IDE 示例现成,文档也很完整。",
},
{
pergunta: "哪款 ESP32 支持 Wi-Fi 6、蓝牙 6 以及 Thread/Zigbee/Matter?",
resposta: "ESP32-C6 和 ESP32-C5 是面向现代网络的主力系列。ESP32-C6 提供 2.4 GHz Wi-Fi 6 和 802.15.4 射频(Zigbee 3.0 / Thread / Matter)。ESP32-C5 则首次在 2.4 GHz 和 5 GHz 两个频段同时支持双频 Wi-Fi 6。",
},
{
pergunta: "做 AI(TinyML)和显示屏,哪款 ESP32 性能最强?",
resposta: "ESP32-P4(400 MHz 双核 RISC-V,带 AI 向量扩展、MIPI-CSI/DSI 接口,最高 64 MB PSRAM)和 ESP32-S3(240 MHz 双核 Xtensa,带神经网络向量加速并支持 RGB LCD)为边缘 AI 和丰富的图形界面提供最高速度。",
},
{
pergunta: "电池供电的项目,哪款 ESP32 最省电?",
resposta: "带有 ULP 协处理器的紧凑型 RISC-V 微控制器,如 ESP32-C2、ESP32-C3 和 ESP32-H2(专用 802.15.4,无 Wi-Fi),深度睡眠电流可低至 5 µA 到 10 µA。",
},
];
export default async function Layout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const faqs = isZh ? faqsZh : isDe ? faqsDe : isFr ? faqsFr : isEs ? faqsEs : isEn ? faqsEn : faqsPt;
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: isZh ? "智能 ESP32 选型器" : isDe
? "Intelligente ESP32-Auswahl"
: isFr
? "Sélecteur intelligent d'ESP32"
: isEs
? "Selector Inteligente de ESP32"
: isEn
? "Intelligent ESP32 Selector"
: "Seletor Inteligente de ESP32",
descricao: isZh ? "交互式工具,分析连接、功耗、外设和安全需求,推荐最合适的 ESP32 系列。" : isDe
? "Interaktives Werkzeug zur Analyse von Konnektivität, Stromverbrauch, Peripherie und Sicherheit zur Ermittlung der idealen ESP32-Serie."
: isFr
? "Outil interactif analysant la connectivité, la consommation, les périphériques et la sécurité pour recommander la série idéale d'ESP32."
: isEs
? "Herramienta interactiva que analiza conectividad, consumo, periféricos y seguridad para recomendar la serie ideal de ESP32."
: isEn
? "Interactive tool analyzing connectivity, power consumption, peripherals, and security to recommend the ideal ESP32 series."
: "Ferramenta interativa que analisa conectividade, consumo, periféricos e segurança para indicar a série ideal de ESP32.",
caminho: isZh ? "/zh-CN/selector" : isDe
? "/de/auswahl"
: isFr
? "/fr/selecteur"
: isEs
? "/es/selector"
: isEn
? "/en/selector"
: "/seletor",
locale,
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{
nome: isZh ? "首页" : isDe ? "Startseite" : isFr ? "Accueil" : isEs ? "Inicio" : isEn ? "Home" : "Início",
caminho: isZh ? "/zh-CN" : isDe ? "/de" : isFr ? "/fr" : isEs ? "/es" : isEn ? "/en" : "/",
},
{
nome: isZh ? "ESP32 选型器" : isDe
? "ESP32-Auswahl"
: isFr
? "Sélecteur d'ESP32"
: isEs
? "Selector de ESP32"
: isEn
? "ESP32 Selector"
: "Seletor de ESP32",
caminho: isZh ? "/zh-CN/selector" : isDe
? "/de/auswahl"
: isFr
? "/fr/selecteur"
: isEs
? "/es/selector"
: isEn
? "/en/selector"
: "/seletor",
},
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+150
View File
@@ -0,0 +1,150 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const meta = paginaMeta({
titulo: isZh ? "ESP32 系列:技术指南与引脚图" : isDe
? "ESP32-Serien: Technischer Leitfaden und Pinbelegung"
: isFr
? "Séries ESP32 : Guide technique et brochage"
: isEs
? "Series ESP32: Guía técnica y patillaje"
: isEn
? "ESP32 Series: Technical Guide and Pinouts"
: "Séries ESP32",
descricao: isZh ? "并排对比全部 12 个 ESP32 系列:ESP32、S2、S3、S31、C2、C3、C5、C6、C61、P4、H2 和 H4。每个系列的架构、内存、无线、外设与引脚图。" : isDe
? "Alle 12 ESP32-Serien Seite an Seite: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 und H4. Architektur, Speicher, Funk, Peripherie und Pinbelegung jeder Serie."
: isFr
? "Les 12 séries d'ESP32 côte à côte : ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 et H4. Architecture, mémoire, radio, périphériques et brochage de chacune."
: isEs
? "Las 12 series de ESP32 lado a lado: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 y H4. Arquitectura, memoria, radio, periféricos y patillaje de cada una."
: isEn
? "All 12 ESP32 series side by side: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 and H4. Architecture, memory, radio, peripherals and pinouts for each one."
: "As 12 séries de ESP32 lado a lado: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 e H4. Arquitetura, memória, rádio, periféricos e pinagem de cada uma, em português.",
caminho: "/series",
locale,
keywords: isZh ? ["ESP32 系列", "ESP32 型号", "ESP32 S3", "ESP32 C6", "ESP32 P4", "ESP32 区别"] : isDe
? ["ESP32-Serien", "ESP32-Modelle", "ESP32 S3", "ESP32 C6", "ESP32 P4", "Unterschied zwischen ESP32"]
: isFr
? ["séries ESP32", "modèles ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "différence entre ESP32"]
: isEs
? ["series ESP32", "modelos de ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "diferencia entre ESP32"]
: isEn
? ["ESP32 series", "ESP32 models", "ESP32 S3", "ESP32 C6", "ESP32 P4", "difference between ESP32"]
: ["séries ESP32", "modelos de ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "diferença entre ESP32"],
});
meta.title = {
default: isZh ? "ESP32 系列" : isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32",
template: "%s · ESPDocs",
};
return meta;
}
const faqsPt = [
{
pergunta: "Quantas séries de ESP32 existem atualmente?",
resposta: "Atualmente o ecossistema Espressif conta com 12 séries principais: ESP32 clássico, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 e ESP32-H4.",
},
{
pergunta: "Quais são as séries mais recentes da Espressif?",
resposta: "As séries mais recentes incluem o ESP32-P4 (focado em alto desempenho com dual-core RISC-V a 400 MHz), o ESP32-C5 (primeiro chip com Wi-Fi dual-band 2.4/5 GHz da Espressif) e o ESP32-C61 (Wi-Fi 6 e Bluetooth 6 de baixo custo).",
},
];
const faqsEn = [
{
pergunta: "How many ESP32 series currently exist?",
resposta: "Currently, the Espressif ecosystem features 12 primary series: classic ESP32, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2, and ESP32-H4.",
},
{
pergunta: "What are the latest series from Espressif?",
resposta: "The newest series include the ESP32-P4 (high-performance dual-core RISC-V at 400 MHz), the ESP32-C5 (first dual-band 2.4/5 GHz Wi-Fi chip from Espressif), and the ESP32-C61 (cost-effective Wi-Fi 6 and Bluetooth 6).",
},
];
const faqsEs = [
{
pergunta: "¿Cuántas series de ESP32 existen actualmente?",
resposta: "Actualmente, el ecosistema de Espressif cuenta con 12 series principales: ESP32 clásico, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 y ESP32-H4.",
},
{
pergunta: "¿Cuáles son las series más recientes de Espressif?",
resposta: "Las series más recientes incluyen el ESP32-P4 (enfocado en alto rendimiento con dual-core RISC-V a 400 MHz), el ESP32-C5 (primer chip con Wi-Fi de doble banda 2.4/5 GHz de Espressif) y el ESP32-C61 (Wi-Fi 6 y Bluetooth 6 de bajo costo).",
},
];
const faqsFr = [
{
pergunta: "Combien de séries d'ESP32 existent actuellement ?",
resposta: "Actuellement, l'écosystème Espressif compte 12 séries principales : ESP32 classique, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 et ESP32-H4.",
},
{
pergunta: "Quelles sont les séries les plus récentes d'Espressif ?",
resposta: "Les séries les plus récentes incluent l'ESP32-P4 (axé sur la haute performance avec dual-core RISC-V à 400 MHz), l'ESP32-C5 (première puce avec Wi-Fi bi-bande 2,4/5 GHz d'Espressif) et l'ESP32-C61 (Wi-Fi 6 et Bluetooth 6 à faible coût).",
},
];
const faqsDe = [
{
pergunta: "Wie viele ESP32-Serien gibt es derzeit?",
resposta: "Derzeit umfasst das Espressif-Ökosystem 12 Hauptserien: klassischer ESP32, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 und ESP32-H4.",
},
{
pergunta: "Welche sind die neuesten Serien von Espressif?",
resposta: "Zu den neuesten Serien gehören der ESP32-P4 (fokussiert auf Hochleistung mit Dual-Core RISC-V bei 400 MHz), der ESP32-C5 (erster Chip mit Dual-Band 2,4/5 GHz Wi-Fi von Espressif) und der ESP32-C61 (kostengünstiges Wi-Fi 6 und Bluetooth 6).",
},
];
const faqsZh = [
{
pergunta: "目前一共有多少个 ESP32 系列?",
resposta: "目前乐鑫生态有 12 个主要系列:经典 ESP32、ESP32-S2、ESP32-S3、ESP32-S31、ESP32-C2、ESP32-C3、ESP32-C5、ESP32-C6、ESP32-C61、ESP32-P4、ESP32-H2 和 ESP32-H4。",
},
{
pergunta: "乐鑫最新的系列有哪些?",
resposta: "最新的系列包括 ESP32-P4(400 MHz 的高性能双核 RISC-V)、ESP32-C5(乐鑫首款 2.4/5 GHz 双频 Wi-Fi 芯片)以及 ESP32-C61(高性价比的 Wi-Fi 6 与蓝牙 6)。",
},
];
export default async function Layout({ children, params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const faqs = isZh ? faqsZh : isDe ? faqsDe : isFr ? faqsFr : isEs ? faqsEs : isEn ? faqsEn : faqsPt;
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{
nome: isZh ? "首页" : isDe ? "Startseite" : isFr ? "Accueil" : isEs ? "Inicio" : isEn ? "Home" : "Início",
caminho: isZh ? "/zh-CN" : isDe ? "/de" : isFr ? "/fr" : isEs ? "/es" : isEn ? "/en" : "/",
},
{
nome: isZh ? "ESP32 系列" : isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32",
caminho: isZh ? "/zh-CN/series" : isDe ? "/de/serien" : isFr ? "/fr/series" : isEs ? "/es/series" : isEn ? "/en/series" : "/series",
},
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
+315
View File
@@ -0,0 +1,315 @@
"use client";
import { useMemo, useState } from "react";
import { usePathname } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Link from "next/link";
import seriesDataPt from "@/public/series.json";
import seriesDataEn from "@/data/en/series.json";
import seriesDataEs from "@/data/es/series.json";
import seriesDataFr from "@/data/fr/series.json";
import seriesDataDe from "@/data/de/series.json";
import seriesDataZh from "@/data/zh-CN/series.json";
import { getLocalizedHref } from "@/i18n/links";
import {
AlertTriangle,
ArrowRight,
ArrowUpRight,
Compass,
Home,
Scale,
ShieldCheck,
Sparkles,
} from "lucide-react";
const FILTROS_PT = [
{ id: "todas", rotulo: "Todas", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Sim" },
{ id: "ia", rotulo: "Aceleração de IA", testa: (s) => Boolean(s.aceleradores_ia) },
];
const FILTROS_EN = [
{ id: "todas", rotulo: "All", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Yes" || s.matter === "Sim" },
{ id: "ia", rotulo: "AI Acceleration", testa: (s) => Boolean(s.aceleradores_ia) },
];
const FILTROS_ES = [
{ id: "todas", rotulo: "Todas", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Yes" || s.matter === "Sim" || s.matter === "Sí" },
{ id: "ia", rotulo: "Aceleración de IA", testa: (s) => Boolean(s.aceleradores_ia) },
];
const FILTROS_FR = [
{ id: "todas", rotulo: "Toutes", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Oui" || s.matter === "Yes" || s.matter === "Sim" || s.matter === "Sí" },
{ id: "ia", rotulo: "Accélération IA", testa: (s) => Boolean(s.aceleradores_ia) },
];
const FILTROS_DE = [
{ id: "todas", rotulo: "Alle", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => (s.matter === "Ja" || s.matter === "是") || s.matter === "Yes" || s.matter === "Sim" || s.matter === "Sí" },
{ id: "ia", rotulo: "KI-Beschleunigung", testa: (s) => Boolean(s.aceleradores_ia) },
];
const FILTROS_ZH = [
{ id: "todas", rotulo: "全部", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => String(s.matter).startsWith("是") },
{ id: "ia", rotulo: "AI 加速", testa: (s) => Boolean(s.aceleradores_ia) },
];
/** Marcador de segurança: o recurso que diferencia a série, não o que todas têm. */
function nivelSeguranca(serie, isEn, isEs, isFr, isDe, isZh = false) {
const seg = serie.seguranca || {};
if (seg.key_manager === "Sim" || seg.key_manager === "Yes" || seg.key_manager === "Sí" || seg.key_manager === "Oui" || (seg.key_manager === "Ja" || seg.key_manager === "是")) return "Key Manager";
if (String(seg.ecdsa).startsWith("Sim") || String(seg.ecdsa).startsWith("Yes") || String(seg.ecdsa).startsWith("Sí") || String(seg.ecdsa).startsWith("Oui") || (String(seg.ecdsa).startsWith("Ja") || String(seg.ecdsa).startsWith("是"))) {
return isZh ? "硬件 ECDSA" : isDe ? "Hardware-ECDSA" : isFr ? "ECDSA matériel" : isEs ? "ECDSA en hardware" : isEn ? "Hardware ECDSA" : "ECDSA em hardware";
}
if (String(seg.ecc).startsWith("Sim") || String(seg.ecc).startsWith("Yes") || String(seg.ecc).startsWith("Sí") || String(seg.ecc).startsWith("Oui") || (String(seg.ecc).startsWith("Ja") || String(seg.ecc).startsWith("是"))) {
return isZh ? "硬件 ECC" : isDe ? "Hardware-ECC" : isFr ? "ECC matériel" : isEs ? "ECC en hardware" : isEn ? "Hardware ECC" : "ECC em hardware";
}
if (String(seg.aes).startsWith("AES")) return "AES + SHA";
return isZh ? "仅 SHA" : isDe ? "Nur SHA" : isFr ? "SHA uniquement" : isEs ? "Solo SHA" : isEn ? "SHA only" : "Só SHA";
}
const simPt = (v) => !String(v).includes("Não");
const simEn = (v) => !String(v).includes("No") && !String(v).includes("Não");
const simEs = (v) => !String(v).includes("No") && !String(v).includes("Não");
const simFr = (v) => !String(v).includes("Non") && !String(v).includes("No") && !String(v).includes("Não");
const simDe = (v) => !(String(v).includes("Nein") || String(v).includes("否")) && !String(v).includes("No") && !String(v).includes("Não");
const simZh = (v) => !String(v).includes("否");
export default function Series() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const currentLocale = isZh ? "zh-CN" : isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt";
const seriesData = isZh ? seriesDataZh : isDe ? seriesDataDe : isFr ? seriesDataFr : isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
const filtros = isZh ? FILTROS_ZH : isDe ? FILTROS_DE : isFr ? FILTROS_FR : isEs ? FILTROS_ES : isEn ? FILTROS_EN : FILTROS_PT;
const [filtro, setFiltro] = useState("todas");
const todas = Object.entries(seriesData);
const ativo = filtros.find((f) => f.id === filtro) || filtros[0];
const series = useMemo(() => todas.filter(([, s]) => ativo.testa(s)), [todas, ativo]);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isZh ? "系列" : isDe ? "Serien" : isFr ? "Séries" : isEs ? "Series" : isEn ? "Series" : "Séries" }]}
icon={Compass}
label={
isZh ? `${todas.length} 个乐鑫系列` : isDe
? `${todas.length} Espressif-Familien`
: isFr
? `${todas.length} familles d'Espressif`
: isEs
? `${todas.length} familias de Espressif`
: isEn
? `${todas.length} Espressif families`
: `${todas.length} famílias da Espressif`
}
title={isZh ? "ESP32 系列" : isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32"}
lede={
isZh ? "每个系列都为特定类型的项目设计,从电池供电的传感器到 AI 加速器。展开卡片可查看引脚、外设与安全特性。" : isDe
? "Jede Serie wurde für einen bestimmten Projekttyp entwickelt, von Batteriesensoren bis hin zu KI-Beschleunigern. Öffnen Sie das Datenblatt für Pinbelegung, Peripherie und Sicherheit."
: isFr
? "Chaque série a été conçue pour un type de projet spécifique, des capteurs sur batterie aux accélérateurs IA. Ouvrez la fiche pour consulter le brochage, les périphériques et la sécurité."
: isEs
? "Cada serie fue diseñada para un tipo de proyecto específico, desde sensores a batería hasta aceleradores de IA. Abra la ficha para ver patillaje, periféricos y seguridad."
: isEn
? "Each series was designed for a specific project type, from battery-powered sensors to AI accelerators. Open the sheet to see pinout, peripherals, and security."
: "Cada série foi desenhada para um tipo de projeto, do sensor a bateria ao acelerador de IA. Abra a ficha para ver pinagem, periféricos e segurança."
}
/>
<section className="shell pt-10 sm:pt-12" aria-label={isZh ? "系列列表" : isDe ? "Serienliste" : isFr ? "Liste des séries" : isEs ? "Lista de series" : isEn ? "Series list" : "Lista de séries"}>
<div role="group" aria-label={isZh ? "筛选系列" : isDe ? "Serien filtern" : isFr ? "Filtrer les séries" : isEs ? "Filtrar series" : isEn ? "Filter series" : "Filtrar séries"} className="flex flex-wrap gap-2">
{filtros.map((f) => (
<button key={f.id} type="button" aria-pressed={filtro === f.id} onClick={() => setFiltro(f.id)} className="chip-btn">
{f.rotulo}
</button>
))}
</div>
<p role="status" aria-live="polite" className="mt-4 text-sm text-muted">
{series.length}{" "}
{series.length === 1
? isZh ? "个系列" : isDe
? "Serie"
: isFr
? "série"
: isEs
? "serie"
: isEn
? "series"
: "série"
: isZh ? "个系列" : isDe
? "Serien"
: isFr
? "séries"
: isEs
? "series"
: isEn
? "series"
: "séries"}
</p>
<div className="mt-4 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{series.map(([key, serie]) => {
const riscv = serie.arquitetura.includes("RISC-V");
const fatos = isZh ? [
["内核", serie.nucleos],
["频率", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simZh(serie.wifi) ? "是" : "否"],
["蓝牙", String(serie.bluetooth).includes("否") ? "否" : "是"],
serie.consumo_energia?.deep_sleep ? ["深度睡眠", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean) : isDe
? [
["Kerne", serie.nucleos],
["Taktfrequenz", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simDe(serie.wifi) ? "Ja" : "Nein"],
["Bluetooth", (String(serie.bluetooth).includes("Nein") || String(serie.bluetooth).includes("否")) || String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "Nein" : "Ja"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean)
: isFr
? [
["Cœurs", serie.nucleos],
["Fréquence", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simFr(serie.wifi) ? "Oui" : "Non"],
["Bluetooth", String(serie.bluetooth).includes("Non") || String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "Non" : "Oui"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean)
: isEs
? [
["Núcleos", serie.nucleos],
["Frecuencia", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simEs(serie.wifi) ? "Sí" : "No"],
["Bluetooth", String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "No" : "Sí"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean)
: isEn
? [
["Cores", serie.nucleos],
["Frequency", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simEn(serie.wifi) ? "Yes" : "No"],
["Bluetooth", String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "No" : "Yes"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean)
: [
["Núcleos", serie.nucleos],
["Frequência", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", simPt(serie.wifi) ? "Sim" : "Não"],
["Bluetooth", serie.bluetooth === "Não" ? "Não" : "Sim"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean);
return (
<Link key={key} href={getLocalizedHref(`/series/${key}`, currentLocale)} className="card card-interactive group flex flex-col p-5 sm:p-6">
<div className="flex items-start justify-between gap-3">
<h2 className="font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{key}</h2>
<span className="chip">{riscv ? "RISC-V" : "Xtensa"}</span>
</div>
<p className="mt-2 line-clamp-2 min-h-[2.9rem] text-sm leading-relaxed text-muted">{serie.descricao}</p>
<dl className="mt-5 divide-y divide-line border-y border-line text-sm">
{fatos.map(([rotulo, valor]) => (
<div key={rotulo} className="flex items-baseline justify-between gap-4 py-2">
<dt className="text-muted">{rotulo}</dt>
<dd className={`text-right font-medium ${valor === "Não" || valor === "No" || valor === "Non" || (valor === "Nein" || valor === "否") ? "text-muted" : "text-ink"}`}>{valor}</dd>
</div>
))}
</dl>
<ul className="mt-4 flex flex-1 flex-wrap content-start gap-1.5">
{serie.aceleradores_ia && (
<li className="chip chip-accent">
<Sparkles className="h-3 w-3" aria-hidden="true" />
{isZh ? "AI 加速器" : isDe ? "KI-Beschleuniger" : isFr ? "Accélérateurs IA" : isEs ? "Aceleradores de IA" : isEn ? "AI Accelerators" : "Aceleradores de IA"}
</li>
)}
<li className="chip">
<ShieldCheck className="h-3 w-3 text-accent" aria-hidden="true" />
{nivelSeguranca(serie, isEn, isEs, isFr, isDe, isZh)}
</li>
{(serie.matter === "Sim" || serie.matter === "Yes" || serie.matter === "Sí" || serie.matter === "Oui" || (serie.matter === "Ja" || serie.matter === "是")) && (
<li className="chip">
<Home className="h-3 w-3 text-accent" aria-hidden="true" />
Matter
</li>
)}
{serie.status_documentacao && (
<li className="chip">
<AlertTriangle className="h-3 w-3 text-gold" aria-hidden="true" />
{isZh ? "初步文档" : isDe ? "Vorläufige Dokumentation" : isFr ? "Documentation préliminaire" : isEs ? "Documentación preliminar" : isEn ? "Preliminary documentation" : "Documentação preliminar"}
</li>
)}
</ul>
<span className="mt-5 inline-flex items-center gap-1 text-sm font-medium text-accent">
{isZh ? "打开数据手册" : isDe ? "Datenblatt öffnen" : isFr ? "Ouvrir la fiche" : isEs ? "Abrir ficha" : isEn ? "Open datasheet" : "Abrir ficha"}
<ArrowUpRight className="h-4 w-4 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
);
})}
</div>
</section>
<section className="shell section">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">
{isZh ? "在两个系列之间犹豫?" : isDe ? "Unsicher zwischen zwei Serien?" : isFr ? "Vous hésitez entre deux séries ?" : isEs ? "¿Tiene dudas entre dos series?" : isEn ? "Unsure between two series?" : "Ficou em dúvida entre duas séries?"}
</h2>
<p className="mt-3 text-base text-muted">
{isZh ? "对比工具可把最多四个型号并排放在一起:内核、无线、内存、外设和安全。" : isDe
? "Der Vergleicher stellt bis zu vier Modelle gegenüber: Kerne, Funk, Speicher, Peripherie und Sicherheit."
: isFr
? "Le comparateur place jusqu'à quatre modèles côte à côte : cœurs, radio, mémoire, périphériques et sécurité."
: isEs
? "El comparador coloca hasta cuatro modelos lado a lado: núcleos, radio, memoria, periféricos y seguridad."
: isEn
? "The comparator tool puts up to four models side by side: cores, radio, memory, peripherals, and security."
: "O comparador coloca até quatro modelos lado a lado: núcleos, rádio, memória, periféricos e segurança."}
</p>
</div>
<Link href={getLocalizedHref("/comparacao", currentLocale)} className="btn btn-primary shrink-0">
<Scale className="h-4 w-4" aria-hidden="true" />
{isZh ? "对比系列" : isDe ? "Serien vergleichen" : isFr ? "Comparer les séries" : isEs ? "Comparar series" : isEn ? "Compare series" : "Comparar séries"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
</main>
<Footer />
</div>
);
}
+365
View File
@@ -0,0 +1,365 @@
import { paginaMeta, jsonLd, SITE } from "@/lib/seo";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Image from "next/image";
import GiteaMark from "@/components/GiteaMark";
import { ArrowUpRight, Code, Globe, GitCompare, Info, Languages } from "lucide-react";
const REPOSITORIO = SITE.repositorio;
export async function generateMetadata({ params }) {
const { locale } = await params;
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
return paginaMeta({
titulo: isZh ? "关于本项目" : isDe
? "Über das Projekt"
: isFr
? "À propos du projet"
: isEs
? "Acerca del proyecto"
: isEn
? "About the Project"
: "Sobre o projeto",
descricao: isZh ? "ESPDocs 是一个独立平台,整理 ESP32 生态的技术文档。了解本项目以及如何参与贡献。" : isDe
? "ESPDocs ist eine unabhängige Plattform, die die technische Dokumentation des ESP32-Ökosystems strukturiert. Erfahren Sie mehr über das Projekt und wie Sie beitragen können."
: isFr
? "ESPDocs est une plateforme indépendante qui organise la documentation technique de l'écosystème ESP32. Découvrez le projet et comment contribuer."
: isEs
? "ESPDocs es una plataforma independiente que organiza la documentación técnica del ecosistema ESP32. Conozca el proyecto y cómo contribuir."
: isEn
? "ESPDocs is an independent platform organizing technical documentation of the ESP32 ecosystem. Learn about the project and how to contribute."
: "O ESPDocs é uma plataforma independente que reúne a documentação do ecossistema ESP32 em português brasileiro. Saiba como o projeto nasceu e como contribuir.",
caminho: "/sobre",
keywords: isZh ? ["ESPDocs", "ESP32 文档", "开源 ESP32 项目"] : isDe
? ["ESPDocs", "ESP32 Dokumentation", "ESP32 Open-Source-Projekt", "Open Source"]
: isFr
? ["ESPDocs", "documentation ESP32", "projet open source ESP32", "open source"]
: isEs
? ["ESPDocs", "documentación ESP32", "proyecto open source ESP32", "código abierto"]
: isEn
? ["ESPDocs", "ESP32 documentation", "open source ESP32 project"]
: ["ESPDocs", "documentação ESP32 português", "projeto open source ESP32"],
locale,
});
}
export default async function Sobre({ params }) {
const { locale } = await params;
const isPt = locale === "pt";
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const featuresPt = [
{ icon: Languages, title: "Em português", desc: "Dados técnicos organizados e apresentados em português do Brasil." },
{ icon: GitCompare, title: "Comparações visuais", desc: "Tabelas e diagramas para escolher a série certa sem abrir dez datasheets." },
{ icon: Globe, title: "Acesso centralizado", desc: "Links diretos para a documentação oficial, repositórios e exemplos." },
{ icon: Code, title: "Código aberto", desc: "Contribuições são bem-vindas no Gitea." },
];
const featuresEn = [
{ icon: Languages, title: "Curated Content", desc: "Structured technical data presented clearly without datasheet noise." },
{ icon: GitCompare, title: "Visual comparisons", desc: "Tables and diagrams to select the right series without opening ten datasheets." },
{ icon: Globe, title: "Centralized access", desc: "Direct links to official documentation, repositories and examples." },
{ icon: Code, title: "Open source", desc: "Contributions are welcome on Gitea." },
];
const featuresEs = [
{ icon: Languages, title: "En español", desc: "Datos técnicos organizados y presentados de forma clara en español neutro." },
{ icon: GitCompare, title: "Comparaciones visuales", desc: "Tablas y diagramas para elegir la serie adecuada sin abrir diez hojas de datos." },
{ icon: Globe, title: "Acceso centralizado", desc: "Enlaces directos a la documentación oficial, repositorios y ejemplos." },
{ icon: Code, title: "Código abierto", desc: "Las contribuciones son bienvenidas en Gitea." },
];
const featuresFr = [
{ icon: Languages, title: "En français", desc: "Données techniques organisées et présentées clairement en français." },
{ icon: GitCompare, title: "Comparaisons visuelles", desc: "Tableaux et schémas pour choisir la bonne série sans ouvrir dix datasheets." },
{ icon: Globe, title: "Accès centralisé", desc: "Liens directs vers la documentation officielle, les dépôts et les exemples." },
{ icon: Code, title: "Open source", desc: "Les contributions sont les bienvenues sur Gitea." },
];
const featuresDe = [
{ icon: Languages, title: "Auf Deutsch", desc: "Technische Daten übersichtlich und strukturiert auf Deutsch aufbereitet." },
{ icon: GitCompare, title: "Visuelle Vergleiche", desc: "Tabellen und Diagramme zur Auswahl der richtigen Serie, ohne zehn Datenblätter zu öffnen." },
{ icon: Globe, title: "Zentraler Zugang", desc: "Direkte Links zu offizieller Dokumentation, Repositories und Beispielen." },
{ icon: Code, title: "Open Source", desc: "Beiträge sind auf Gitea herzlich willkommen." },
];
const featuresZh = [
{ icon: Languages, title: "精心整理的内容", desc: "结构化的技术数据,清晰呈现,没有数据手册的冗余。" },
{ icon: GitCompare, title: "可视化对比", desc: "用表格和图示选出合适的系列,无需翻阅十份数据手册。" },
{ icon: Globe, title: "集中入口", desc: "直达官方文档、代码仓库与示例的链接。" },
{ icon: Code, title: "开源", desc: "欢迎在 Gitea 上贡献。" },
];
const features = isZh ? featuresZh : isDe ? featuresDe : isFr ? featuresFr : isEs ? featuresEs : isEn ? featuresEn : featuresPt;
return (
<div className="site-canvas min-h-screen">
{/* Metadados E-E-A-T de autoria e organização para o Google */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.paginaSobre(locale)) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: isZh ? "首页" : isDe ? "Startseite" : isFr ? "Accueil" : isEs ? "Inicio" : isPt ? "Início" : "Home", caminho: isZh ? "/zh-CN" : isDe ? "/de" : isFr ? "/fr" : isEn ? "/en" : isEs ? "/es" : "/" },
{ nome: isZh ? "关于本项目" : isDe ? "Über das Projekt" : isFr ? "À propos du projet" : isEs ? "Acerca del proyecto" : isPt ? "Sobre o Projeto" : "About the Project", caminho: isZh ? "/zh-CN/about" : isDe ? "/de/ueber-uns" : isFr ? "/fr/a-propos" : isEn ? "/en/about" : isEs ? "/es/acerca" : "/sobre" },
])
),
}}
/>
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isZh ? "关于" : isDe ? "Über uns" : isFr ? "À propos" : isEs ? "Acerca" : isPt ? "Sobre" : "About" }]}
icon={Info}
label={isZh ? "独立项目" : isDe ? "Unabhängiges Projekt" : isFr ? "Projet indépendant" : isEs ? "Proyecto independiente" : isPt ? "Projeto independente" : "Independent project"}
title={isZh ? "关于 ESPDocs" : isDe ? "Über ESPDocs" : isFr ? "À propos d'ESPDocs" : isEs ? "Acerca de ESPDocs" : isPt ? "Sobre o ESPDocs" : "About ESPDocs"}
lede={
isZh ? "一个非官方平台,整理 ESP32 的技术信息,并直接链接到乐鑫官方文档。为开源硬件社区而做。" : isDe
? "Eine inoffizielle deutschsprachige Plattform, die technische Informationen zum ESP32 strukturiert und Sie mit der offiziellen Dokumentation von Espressif verbindet. Entwickelt für die Open-Hardware-Community."
: isFr
? "Une plateforme non officielle en français qui organise les informations techniques de l'ESP32 et vous oriente vers la documentation officielle d'Espressif. Conçue pour la communauté du matériel libre."
: isEs
? "Una plataforma no oficial, en español, que organiza la información técnica del ESP32 y le conecta con la documentación oficial de Espressif. Creada para la comunidad de hardware abierto."
: isPt
? "Uma plataforma não oficial, em português, que organiza as informações técnicas do ESP32 e leva você à documentação oficial da Espressif. Feita para a comunidade de hardware livre."
: "An unofficial platform organizing technical information about the ESP32 and linking directly to official Espressif documentation. Built for the open hardware community."
}
>
<a href={REPOSITORIO} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
<GiteaMark className="h-4 w-4" />
{isZh ? "查看代码仓库" : isDe ? "Repository ansehen" : isFr ? "Voir le dépôt" : isEs ? "Ver el repositorio" : isPt ? "Ver o repositório" : "View repository"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</PageHero>
<div className="shell section grid grid-cols-1 gap-10 pt-12 sm:pt-16 lg:grid-cols-[1fr_22rem] lg:gap-14">
<div className="min-w-0 max-w-3xl space-y-12">
<section aria-labelledby="missao">
<h2 id="missao" className="section-title">{isZh ? "使命" : isDe ? "Mission" : isFr ? "Mission" : isEs ? "Misión" : isPt ? "Missão" : "Mission"}</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
{isZh ? "通过一个整理规格、对比系列、介绍框架并集中官方文档链接的界面,让 ESP32 生态更易获取、更易理解。目标是节省固件与物联网项目的开发时间。" : isDe
? "Den Zugang zum und das Verständnis für das ESP32-Ökosystem durch eine deutsche Oberfläche erleichtern, die Spezifikationen bündelt, Serien vergleicht, Frameworks vorstellt und offizielle Dokumentationslinks zentralisiert. Ziel ist es, Entwicklungszeit bei Firmware und IoT-Projekten zu sparen."
: isFr
? "Faciliter l'accès et la compréhension de l'écosystème ESP32 avec une interface en français qui organise les spécifications, compare les séries, présente les frameworks et centralise les liens vers la documentation officielle. L'objectif est de vous faire gagner du temps dans le développement de firmware et d'IoT."
: isEs
? "Facilitar el acceso y la comprensión del ecosistema ESP32 con una interfaz en español que organiza especificaciones, compara series, presenta frameworks y centraliza los enlaces a la documentación oficial. El objetivo es ahorrar tiempo en el desarrollo de firmware e IoT."
: isPt
? "Facilitar o acesso e a compreensão do ecossistema ESP32 com uma interface em português que organiza especificações, compara séries, apresenta frameworks e centraliza os links da documentação oficial. O objetivo é economizar o seu tempo no desenvolvimento de firmware e IoT."
: "Facilitate access and understanding of the ESP32 ecosystem with an interface organizing specifications, comparing series, presenting frameworks and centralizing links to official documentation. The goal is to save development time in firmware and IoT projects."}
</p>
</section>
<section aria-labelledby="porque">
<h2 id="porque" className="section-title">{isZh ? "ESPDocs 为什么存在" : isDe ? "Warum es ESPDocs gibt" : isFr ? "Pourquoi ESPDocs existe" : isEs ? "¿Por qué existe ESPDocs?" : isPt ? "Por que o ESPDocs existe" : "Why ESPDocs exists"}</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
{isZh ? "ESP32 的信息常常分散在冗长的数据手册、技术参考手册(TRM)和零散的代码仓库中。ESPDocs 把这些数据浓缩并结构化,便于在深入工程文档之前快速评估。" : isDe
? "Informationen über den ESP32 sind oft über dichte Datenblätter, technische Referenzhandbücher (TRM) und sekundäre Repositories verstreut. ESPDocs verdichtet und strukturiert diese Daten für eine schnelle Vorabauswahl, bevor Sie tiefer in die offizielle Technik einsteigen."
: isFr
? "Les informations sur l'ESP32 sont souvent dispersées entre des fiches techniques denses, des manuels de référence technique (TRM) et des dépôts secondaires. ESPDocs condense et structure ces données pour une évaluation rapide avant d'approfondir l'ingénierie officielle."
: isEs
? "La información sobre el ESP32 suele estar dispersa entre hojas de datos densas, manuales de referencia técnica (TRM) y repositorios secundarios. ESPDocs condensa y estructura estos datos para una evaluación rápida antes de profundizar en la ingeniería oficial."
: isPt
? "As informações sobre os ESP32 costumam estar espalhadas entre datasheets densos, manuais de referência (TRM) e repositórios secundários, tudo em inglês. O ESPDocs condensa e estrutura esses dados para a triagem rápida, antes de você aprofundar na engenharia oficial."
: "Information regarding the ESP32 is often scattered across dense datasheets, Technical Reference Manuals (TRM), and secondary repositories. ESPDocs condenses and structures this data for rapid evaluation before diving into in-depth engineering documentation."}
</p>
<ul className="mt-6 grid gap-3 sm:grid-cols-2">
{features.map(({ icon: Icon, title, desc }) => (
<li key={title} className="card flex items-start gap-4 p-5">
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<div>
<h3 className="font-semibold text-ink">{title}</h3>
<p className="mt-1 text-sm leading-relaxed text-muted">{desc}</p>
</div>
</li>
))}
</ul>
</section>
<section aria-labelledby="contribuir">
<h2 id="contribuir" className="section-title">{isZh ? "如何参与贡献" : isDe ? "Wie Sie beitragen können" : isFr ? "Comment contribuer" : isEs ? "Cómo contribuir" : isPt ? "Como contribuir" : "How to contribute"}</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
{isZh ? "欢迎提交翻译修正、表格改进和新的代码示例。项目与社区一同成长。" : isDe
? "Übersetzungskorrekturen, Tabellenanpassungen und neue Codebeispiele sind herzlich willkommen. Das Projekt wächst gemeinsam mit der Community."
: isFr
? "Les corrections de traduction, les ajustements de tableaux et les nouveaux exemples de code sont très appréciés. Le projet grandit avec la communauté."
: isEs
? "Las correcciones de traducción, ajustes en tablas y nuevos ejemplos de código son muy bienvenidos. El proyecto crece junto con la comunidad."
: isPt
? "Correções de tradução, ajustes em tabelas e novos exemplos de código são muito bem-vindos. O projeto cresce com a comunidade."
: "Translation fixes, table refinements and new code examples are welcome. The project grows with the community."}
</p>
<ol className="mt-6 space-y-3">
{(isZh ? ["在 Gitea 上 Fork 本仓库。", "实现改进,并核对官方技术资料。", "发起 Pull Request 并说明改动。"] : isDe
? [
"Erstellen Sie einen Fork des Repositories auf Gitea.",
"Implementieren Sie die Verbesserungen und prüfen Sie die offiziellen technischen Referenzen.",
"Eröffnen Sie einen Pull Request mit einer Beschreibung der vorgenommenen Änderungen.",
]
: isFr
? [
"Forkez le dépôt sur Gitea.",
"Apportez les améliorations et vérifiez les références techniques officielles.",
"Ouvrez une Pull Request décrivant les modifications apportées.",
]
: isEs
? [
"Haga un fork del repositorio en Gitea.",
"Implemente las mejoras y verifique las referencias técnicas oficiales.",
"Abra una solicitud de extracción (Pull Request) describiendo los cambios realizados.",
]
: isPt
? [
"Faça o fork do repositório no Gitea.",
"Implemente as melhorias e confira as referências técnicas oficiais.",
"Abra um Pull Request descrevendo os ajustes feitos.",
]
: [
"Fork the repository on Gitea.",
"Implement improvements and verify official technical references.",
"Open a Pull Request describing the changes.",
]
).map((passo, i) => (
<li key={passo} className="card flex items-center gap-4 px-5 py-4">
<span className="grid h-8 w-8 shrink-0 place-items-center rounded-full bg-ink text-sm font-semibold text-canvas" aria-hidden="true">
{i + 1}
</span>
<span className="text-sm text-ink-soft sm:text-base">{passo}</span>
</li>
))}
</ol>
</section>
<section aria-labelledby="acessibilidade">
<h2 id="acessibilidade" className="section-title">{isZh ? "无障碍" : isDe ? "Barrierefreiheit" : isFr ? "Accessibilité" : isEs ? "Accesibilidad" : isPt ? "Acessibilidade" : "Accessibility"}</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
{isZh ? "ESPDocs 重视可读性、高对比度(WCAG AAA 级)和完整的键盘导航。如果你遇到任何无障碍或导航上的障碍,请在代码仓库中提交 issue。" : isDe
? "ESPDocs legt großen Wert auf Lesbarkeit, hohen Kontrast (WCAG-Stufe AAA) und vollständige Tastaturnavigation. Wenn Sie auf Lese- oder Navigationsbarrieren stoßen, eröffnen Sie bitte ein Issue im Repository."
: isFr
? "ESPDocs privilégie la lisibilité, un contraste élevé (niveau AAA du WCAG) et une navigation complète au clavier. Si vous rencontrez un obstacle de lecture ou de navigation, ouvrez un ticket dans le dépôt."
: isEs
? "ESPDocs prioriza la legibilidad, el alto contraste (nivel AAA de WCAG) y la navegación completa por teclado. Si encuentra alguna barrera de lectura o navegación, abra un issue en el repositorio."
: isPt
? "O ESPDocs prioriza a legibilidade, o contraste alto (nível AAA da WCAG) e a navegação completa por teclado. Se encontrar alguma barreira de leitura ou navegação, abra uma issue no repositório."
: "ESPDocs prioritizes readability, high contrast (WCAG AAA level), and full keyboard navigation. If you encounter any accessibility or navigation hurdles, please open an issue in the repository."}
</p>
</section>
</div>
<aside className="space-y-5 lg:sticky lg:top-28 lg:self-start" aria-label={isZh ? "作者与法律声明" : isDe ? "Autor und rechtlicher Hinweis" : isFr ? "Auteur et mentions légales" : isEs ? "Autor y aviso legal" : isPt ? "Autor e aviso legal" : "Author and legal notice"}>
<div className="panel p-6 sm:p-7">
<div className="flex items-center gap-4">
<span className="grid h-16 w-16 shrink-0 place-items-center rounded-2xl border border-line bg-white">
<Image src="/logo.png" alt="" aria-hidden="true" width={48} height={48} className="h-12 w-12 object-contain" />
</span>
<div>
<h2 className="font-display text-lg font-semibold text-ink">Lucas Rayan Guerra</h2>
<p className="text-sm text-muted">{isZh ? "Ciência Embarcada 创始人" : isDe ? "Gründer von Ciência Embarcada" : isFr ? "Créateur de Ciência Embarcada" : isEs ? "Creador de Ciência Embarcada" : isPt ? "Criador do Ciência Embarcada" : "Creator of Ciência Embarcada"}</p>
</div>
</div>
<div className="mt-5 space-y-3 text-sm leading-relaxed text-muted">
{isZh ? (
<>
<p>
系统开发技术员,UFRPE 计算机科学在读,区块链与密码学研究者。
</p>
<p>
Semine AgriTech 软件总监,并在 REC&apos;n&apos;Play 等活动中作演讲,分享硬件、物联网和网络安全方面的见解。
</p>
</>
) : isDe ? (
<>
<p>
Systementwicklungstechniker, Informatikstudent an der UFRPE und Forscher im Bereich Blockchain und Kryptographie.
</p>
<p>
Software-Direktor bei Semine AgriTech und Referent bei Veranstaltungen wie REC&apos;n&apos;Play, der Inhalte zu Hardware, IoT und Cybersicherheit vermittelt.
</p>
</>
) : isFr ? (
<>
<p>
Technicien en développement de systèmes, étudiant en informatique à l'UFRPE et chercheur en blockchain et cryptographie.
</p>
<p>
Directeur logiciel chez Semine AgriTech et conférencier lors d'événements comme REC&apos;n&apos;Play, partageant des connaissances sur le matériel, l'IoT et la cybersécurité.
</p>
</>
) : isEs ? (
<>
<p>
Técnico en Desarrollo de Sistemas, estudiante de Ciencias de la Computación en la UFRPE e investigador en Blockchain y Criptografía.
</p>
<p>
Director de Software en Semine AgriTech y ponente en eventos como REC&apos;n&apos;Play, compartiendo contenido sobre hardware, IoT y ciberseguridad.
</p>
</>
) : isPt ? (
<>
<p>
Técnico em Desenvolvimento de Sistemas, estudante de Ciência da Computação na UFRPE e pesquisador de
Blockchain e Criptografia.
</p>
<p>
Diretor de Software na Semine AgriTech e palestrante em eventos como o REC&apos;n&apos;Play, compartilha
conteúdo sobre hardware, IoT e cibersegurança.
</p>
</>
) : (
<>
<p>
Systems development technician, Computer Science student at UFRPE, and researcher in Blockchain and Cryptography.
</p>
<p>
Software Director at Semine AgriTech and speaker at events like REC&apos;n&apos;Play, sharing insights on hardware, IoT, and cybersecurity.
</p>
</>
)}
</div>
<a href="https://cienciaembarcada.com.br" target="_blank" rel="noopener noreferrer" className="btn btn-ghost mt-6 w-full">
{isZh ? "访问 Ciência Embarcada" : isDe ? "Ciência Embarcada besuchen" : isFr ? "Visiter Ciência Embarcada" : isEs ? "Visitar Ciência Embarcada" : isPt ? "Visitar o Ciência Embarcada" : "Visit Ciência Embarcada"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</div>
<div className="callout callout-warn">
<p className="font-semibold text-ink">{isZh ? "法律声明" : isDe ? "Rechtlicher Hinweis" : isFr ? "Mentions légales" : isEs ? "Aviso legal" : isPt ? "Aviso legal" : "Legal notice"}</p>
<p className="mt-1">
{isZh ? "ESPDocs 是一个聚合与整理平台。所引用的手册和代码仓库归乐鑫系统(Espressif Systems)所有。在关键任务或商业设计中,请始终查阅官方文档。" : isDe
? "ESPDocs ist ein Aggregator und Kurator. Die referenzierten Handbücher und Repositories sind Eigentum von Espressif Systems. Konsultieren Sie bei geschäftskritischen oder kommerziellen Projekten stets die offizielle Dokumentation."
: isFr
? "ESPDocs est une plateforme d'agrégation et de synthèse. Les manuels et dépôts référencés appartiennent à Espressif Systems. Pour les projets critiques ou commerciaux, consultez systématiquement la documentation officielle."
: isEs
? "ESPDocs es un agregador y organizador. Los manuales y repositorios referenciados pertenecen a Espressif Systems. En proyectos críticos o comerciales, consulte siempre la documentación oficial."
: isPt
? "O ESPDocs é um agregador e organizador. Os manuais e repositórios referenciados pertencem à Espressif Systems. Em projetos críticos ou comerciais, consulte sempre a documentação oficial."
: "ESPDocs is an aggregator and curation platform. Referenced manuals and repositories are property of Espressif Systems. In mission-critical or commercial designs, always consult official documentation."}
</p>
</div>
</aside>
</div>
</main>
<Footer />
</div>
);
}
+17
View File
@@ -0,0 +1,17 @@
import { construirIndiceBusca } from "@/lib/searchIndex";
export const dynamic = "force-static";
export function generateStaticParams() {
return [{ locale: "pt" }, { locale: "en" }, { locale: "es" }, { locale: "fr" }, { locale: "de" }, { locale: "zh-CN" }];
}
export async function GET(request, { params }) {
const { locale } = await params;
const loc = ["en", "es", "fr", "de", "zh-CN"].includes(locale) ? locale : "pt";
return Response.json(construirIndiceBusca(loc), {
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
},
});
}
+12
View File
@@ -0,0 +1,12 @@
import { construirIndiceBusca } from "@/lib/searchIndex";
export const dynamic = "force-static";
/** Índice de busca carregado sob demanda pelo diálogo de pesquisa (Ctrl/⌘+K). */
export function GET() {
return Response.json(construirIndiceBusca(), {
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
},
});
}
-39
View File
@@ -1,39 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Catálogo de placas ESP32",
descricao: "Placas de desenvolvimento com ESP32 disponíveis no Brasil, com filtro por série, conector e conversor USB-serial.",
caminho: "/catalogo",
keywords: ["placas ESP32", "DevKit ESP32", "comprar ESP32", "ESP32 DevKitC"],
});
export default function Layout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Catálogo de Placas ESP32",
descricao: "Guia e catálogo interativo de placas de desenvolvimento e DevKits com microcontroladores ESP32.",
caminho: "/catalogo",
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Catálogo de Placas", caminho: "/catalogo" },
])
),
}}
/>
{children}
</>
);
}
-325
View File
@@ -1,325 +0,0 @@
"use client";
import { useState, useEffect } from 'react';
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import BoardCard from "@/components/BoardCard";
import { AlertTriangle, RefreshCw, Search, ShoppingCart, SlidersHorizontal } from "lucide-react";
export default function PlacasPage() {
const [boards, setBoards] = useState([]);
const [filteredBoards, setFilteredBoards] = useState([]);
const [headers, setHeaders] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [searchTerm, setSearchTerm] = useState('');
const [activeFilters, setActiveFilters] = useState({});
const [filterOptions, setFilterOptions] = useState({});
const [filtrosAbertos, setFiltrosAbertos] = useState(false);
const excludedColumns = ['Nome', 'Descrição', 'Link', 'Imagem', 'Loja Oficial'];
useEffect(() => {
fetchBoards();
// No desktop os filtros ficam sempre à vista; no celular começam recolhidos.
setFiltrosAbertos(window.matchMedia('(min-width: 1024px)').matches);
}, []);
useEffect(() => {
applyFilters();
}, [boards, searchTerm, activeFilters]);
const fetchBoards = async () => {
try {
setLoading(true);
const response = await fetch('/api/placas');
if (!response.ok) {
throw new Error('Erro ao carregar dados das placas');
}
const result = await response.json();
setBoards(result.data);
setHeaders(result.headers);
setFilteredBoards(result.data);
generateFilterOptions(result.data, result.headers);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const generateFilterOptions = (data, headers) => {
const options = {};
const filterableColumns = headers.filter(h => !excludedColumns.includes(h));
filterableColumns.forEach(column => {
const uniqueValues = new Set();
data.forEach(item => {
const value = item[column];
if (value && value.toString().trim()) {
uniqueValues.add(value.toString().trim());
}
});
const values = Array.from(uniqueValues).sort();
// Verificar se é um filtro binário (apenas Sim/Não/Opcional)
const binaryValues = ['Sim', 'Não', 'Opcional'];
const isBinaryFilter = values.every(v => binaryValues.includes(v));
options[column] = {
values: values,
isBinary: isBinaryFilter
};
});
setFilterOptions(options);
};
const applyFilters = () => {
let filtered = [...boards];
if (searchTerm) {
filtered = filtered.filter(board => {
const searchLower = searchTerm.toLowerCase();
return (
board.Nome?.toLowerCase().includes(searchLower) ||
board.Descrição?.toLowerCase().includes(searchLower)
);
});
}
Object.keys(activeFilters).forEach(column => {
if (activeFilters[column] && activeFilters[column].length > 0) {
filtered = filtered.filter(board => {
const boardValue = board[column]?.toString().trim();
// Para filtros binários, o valor armazenado é 'binary-enabled'
if (activeFilters[column].includes('binary-enabled')) {
return boardValue === 'Sim' || boardValue === 'Opcional';
}
return activeFilters[column].includes(boardValue);
});
}
});
setFilteredBoards(filtered);
};
const handleFilterToggle = (column, value) => {
setActiveFilters(prev => {
const newFilters = { ...prev };
if (!newFilters[column]) {
newFilters[column] = [value];
} else {
const index = newFilters[column].indexOf(value);
if (index > -1) {
// Remove o valor
newFilters[column] = newFilters[column].filter(v => v !== value);
if (newFilters[column].length === 0) {
delete newFilters[column];
}
} else {
// Adiciona o valor
newFilters[column] = [...newFilters[column], value];
}
}
return newFilters;
});
};
const clearFilters = () => {
setActiveFilters({});
setSearchTerm('');
};
const activeFilterCount = Object.keys(activeFilters).length + (searchTerm ? 1 : 0);
const filterableColumns = headers.filter((h) => !excludedColumns.includes(h));
const hero = (
<PageHero
trail={[{ label: "Catálogo de placas" }]}
icon={ShoppingCart}
label="DevKits e módulos reais"
title="Catálogo de placas ESP32"
lede="Compare placas oficiais e alternativas para o seu projeto: interface USB, sensores integrados e link direto para a loja."
/>
);
if (loading) {
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10" aria-busy="true" aria-label="Carregando placas">
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="card h-72 animate-pulse bg-surface-2" />
))}
</div>
<p role="status" className="mt-6 text-center text-sm text-muted">Consultando o banco de placas…</p>
</section>
</main>
<Footer />
</div>
);
}
if (error) {
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10">
<div role="alert" className="callout callout-danger flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-danger" aria-hidden="true" />
<div>
<p className="font-semibold text-ink">Não foi possível carregar as placas</p>
<p className="mt-1">{error}. Verifique a conexão e tente de novo.</p>
<button type="button" onClick={fetchBoards} className="btn btn-primary btn-sm mt-4">
<RefreshCw className="h-4 w-4" aria-hidden="true" />
Tentar novamente
</button>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
const filtros = (
<div className="space-y-6">
<div>
<label htmlFor="busca-placa" className="text-sm font-semibold text-ink">
Buscar placa
</label>
<div className="relative mt-2">
<Search className="pointer-events-none absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-placa"
type="search"
placeholder="Nome ou descrição"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="field pl-10 text-sm"
/>
</div>
</div>
{filterableColumns.map((column) => {
const filterData = filterOptions[column];
if (!filterData) return null;
if (filterData.isBinary) {
return (
<label key={column} className="flex min-h-11 cursor-pointer items-center justify-between gap-3 border-t border-line pt-4 text-sm font-medium text-ink-soft">
{column}
<input
type="checkbox"
checked={activeFilters[column]?.includes("binary-enabled") || false}
onChange={() => handleFilterToggle(column, "binary-enabled")}
className="h-5 w-5 shrink-0 cursor-pointer accent-[var(--accent)]"
/>
</label>
);
}
return (
<fieldset key={column} className="border-t border-line pt-4">
<legend className="flex items-center gap-2 pr-2 text-sm font-semibold text-ink">
{column}
{activeFilters[column]?.length > 0 && <span className="chip chip-accent px-2 py-0">{activeFilters[column].length}</span>}
</legend>
<div className="mt-2 max-h-44 space-y-0.5 overflow-y-auto pr-1">
{filterData.values.map((option) => (
<label key={option} className="flex min-h-10 cursor-pointer items-center gap-3 rounded-lg px-2 text-sm text-muted transition-colors hover:bg-surface-2 hover:text-ink">
<input
type="checkbox"
checked={activeFilters[column]?.includes(option) || false}
onChange={() => handleFilterToggle(column, option)}
className="h-4 w-4 shrink-0 cursor-pointer accent-[var(--accent)]"
/>
{option}
</label>
))}
</div>
</fieldset>
);
})}
</div>
);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
{hero}
<section className="shell section pt-10 sm:pt-12" aria-label="Placas">
<div className="grid gap-8 lg:grid-cols-[17rem_1fr] lg:gap-10">
<aside className="lg:sticky lg:top-28 lg:self-start">
<details className="panel" open={filtrosAbertos} onToggle={(e) => setFiltrosAbertos(e.currentTarget.open)}>
<summary className="flex min-h-12 cursor-pointer list-none items-center justify-between gap-3 px-5 py-3 lg:cursor-default">
<span className="flex items-center gap-2 text-sm font-semibold text-ink">
<SlidersHorizontal className="h-4 w-4 text-accent" aria-hidden="true" />
Filtros
{activeFilterCount > 0 && <span className="chip chip-accent px-2 py-0">{activeFilterCount}</span>}
</span>
{activeFilterCount > 0 && (
<button
type="button"
onClick={(e) => { e.preventDefault(); clearFilters(); }}
className="text-sm font-medium text-accent hover:text-accent-strong"
>
Limpar
</button>
)}
</summary>
<div className="border-t border-line p-5 lg:max-h-[calc(100vh-11rem)] lg:overflow-y-auto">{filtros}</div>
</details>
</aside>
<div>
<p role="status" aria-live="polite" className="text-sm text-muted">
<strong className="font-semibold text-ink">{filteredBoards.length}</strong>{" "}
{filteredBoards.length === 1 ? "placa encontrada" : "placas encontradas"}
</p>
{filteredBoards.length === 0 ? (
<div className="card mt-4 px-6 py-14 text-center">
<Search className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h2 className="mt-4 font-display text-xl font-semibold text-ink">Nenhuma placa com esses filtros</h2>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">Remova alguns filtros ou busque por outro nome.</p>
<button type="button" onClick={clearFilters} className="btn btn-primary mt-6">
Limpar filtros
</button>
</div>
) : (
<div className="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{filteredBoards.map((board, index) => (
<BoardCard key={index} board={board} />
))}
</div>
)}
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
-60
View File
@@ -1,60 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Comparar séries ESP32",
descricao: "Compare até quatro séries de ESP32 lado a lado: processador, Wi-Fi, Bluetooth, memória, GPIO, periféricos e segurança em hardware, com os dados dos datasheets oficiais.",
caminho: "/comparacao",
keywords: ["comparar ESP32", "ESP32 vs ESP32-S3", "tabela comparativa ESP32", "qual ESP32 é melhor"],
});
const faqs = [
{
pergunta: "Como comparar microcontroladores ESP32 lado a lado?",
resposta: "O comparador do ESPDocs permite selecionar até quatro séries simultaneamente para confrontar arquitetura, frequência de clock, memória SRAM/PSRAM, padrões de rádio (Wi-Fi 4/6, Bluetooth 5/6, 802.15.4), interfaces de periféricos e blocos de segurança em hardware.",
},
{
pergunta: "Qual a diferença entre o ESP32 clássico e o ESP32-S3?",
resposta: "O ESP32 clássico usa núcleos Xtensa LX6 e Bluetooth clássico/LE. O ESP32-S3 traz núcleos Xtensa LX7 com instruções vetoriais para inteligência artificial (TinyML), USB nativo OTG, mais GPIOs (45 contra 36) e Bluetooth 5.0 LE.",
},
{
pergunta: "Qual a diferença entre ESP32-C3 e ESP32-C6?",
resposta: "O ESP32-C3 é um microcontrolador RISC-V com Wi-Fi 4 e Bluetooth 5 LE. O ESP32-C6 evolui para Wi-Fi 6 (802.11ax), Bluetooth 5.4 LE, rádio IEEE 802.15.4 para Zigbee 3.0 e Thread 1.3, além de coprocessador de ultrabaixo consumo.",
},
];
export default function Layout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Comparador de Séries ESP32",
descricao: "Tabela comparativa técnica para analisar especificações, pinagens e recursos de múltiplas séries de ESP32.",
caminho: "/comparacao",
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Comparar Séries", caminho: "/comparacao" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
-306
View File
@@ -1,306 +0,0 @@
"use client";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import { useEffect, useState, Fragment } from "react";
import Link from "next/link";
import seriesData from "@/public/series.json";
import { ArrowRight, ArrowUpRight, Check, ChevronDown, Scale } from "lucide-react";
const MIN_SERIES = 2;
const MAX_SERIES = 4;
/* Lê "seguranca.ecc" além de chaves simples. */
function valorDe(objeto, caminho) {
return caminho.split(".").reduce((atual, parte) => atual?.[parte], objeto);
}
export default function Comparacao() {
const [selectedSeries, setSelectedSeries] = useState(["ESP32", "ESP32-S3"]);
const [soDiferencas, setSoDiferencas] = useState(false);
const [collapsedCategories, setCollapsedCategories] = useState({
"Interfaces Especiais": true,
"Especificações Ambientais": true,
});
const series = Object.entries(seriesData);
// O seletor envia as séries finalistas em ?chips=ESP32-S3,ESP32-C6.
useEffect(() => {
const chips = new URLSearchParams(window.location.search).get("chips");
if (!chips) return;
const validas = [...new Set(chips.split(","))].filter((k) => seriesData[k]).slice(0, MAX_SERIES);
if (validas.length >= MIN_SERIES) setSelectedSeries(validas);
}, []);
const toggleSeries = (seriesKey) => {
if (selectedSeries.includes(seriesKey)) {
if (selectedSeries.length > MIN_SERIES) setSelectedSeries(selectedSeries.filter((s) => s !== seriesKey));
} else if (selectedSeries.length < MAX_SERIES) {
setSelectedSeries([...selectedSeries, seriesKey]);
}
};
const toggleCategory = (category) => {
setCollapsedCategories({ ...collapsedCategories, [category]: !collapsedCategories[category] });
};
const compareFields = [
{ category: "Geral", fields: [
{ key: "nome_completo", label: "Nome Completo" },
{ key: "descricao", label: "Descrição" },
]},
{ category: "Disponibilidade e Ferramentas", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF mínimo" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "encapsulamento", label: "Encapsulamento" },
{ key: "modulos", label: "Módulos disponíveis" },
]},
{ category: "Processador", fields: [
{ key: "arquitetura", label: "Arquitetura" },
{ key: "nucleos", label: "Núcleos" },
{ key: "frequencia", label: "Frequência" },
{ key: "coprocessador_ulp", label: "Coprocessador ULP" },
{ key: "aceleradores_ia", label: "Aceleradores de IA" },
]},
{ category: "Conectividade", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memória", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash Externa" },
{ key: "psram_externa", label: "PSRAM Externa" },
]},
{ category: "Periféricos Digitais", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Periféricos Analógicos", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch Capacitivo" },
{ key: "sensor_hall", label: "Sensor Hall" },
{ key: "sensor_temperatura", label: "Sensor de Temperatura" },
]},
{ category: "Segurança", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (curvas elípticas)" },
{ key: "seguranca.ecdsa", label: "ECDSA em hardware" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Assinatura Digital (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Gerador aleatório (RNG)" },
{ key: "seguranca.criptografia_flash", label: "Criptografia de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Proteção contra DPA" },
]},
{ category: "Interfaces Especiais", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Câmera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Especificações Ambientais", fields: [
{ key: "temperatura_operacao", label: "Temp. Operação" },
{ key: "temperatura_armazenamento", label: "Temp. Armazenamento" },
]},
];
const renderValue = (value) => {
if (!value || value === "Não") return <span className="text-muted">Não</span>;
if (value === "Sim") {
return (
<span className="inline-flex items-center gap-1.5 font-medium text-ok">
<Check className="h-4 w-4" aria-hidden="true" />
Sim
</span>
);
}
return <span className="font-medium text-ink">{value}</span>;
};
const valores = (key) => selectedSeries.map((k) => String(valorDe(seriesData[k], key) ?? "Não"));
const diferem = (key) => new Set(valores(key)).size > 1;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Comparador" }]}
icon={Scale}
label="Até quatro séries lado a lado"
title="Comparador de séries"
lede="Coloque núcleos, rádio, memória, periféricos e segurança na mesma tabela e veja o que realmente muda de um chip para outro."
/>
<section className="shell pt-10 sm:pt-12" aria-labelledby="escolha-titulo">
<div className="panel p-5 sm:p-7">
<div className="flex flex-wrap items-end justify-between gap-3">
<div>
<h2 id="escolha-titulo" className="text-base font-semibold text-ink">Escolha de {MIN_SERIES} a {MAX_SERIES} séries</h2>
<p role="status" aria-live="polite" className="mt-1 text-sm text-muted">
{selectedSeries.length} de {MAX_SERIES} selecionadas
{selectedSeries.length === MAX_SERIES && ". Remova uma para trocar."}
</p>
</div>
</div>
<div className="mt-4 flex flex-wrap gap-2">
{series.map(([key]) => {
const marcada = selectedSeries.includes(key);
const bloqueada = !marcada && selectedSeries.length >= MAX_SERIES;
return (
<button
key={key}
type="button"
onClick={() => toggleSeries(key)}
aria-pressed={marcada}
aria-disabled={bloqueada}
className={`chip-btn ${bloqueada ? "opacity-50" : ""}`}
>
{marcada && <Check className="h-4 w-4" aria-hidden="true" />}
{key}
</button>
);
})}
</div>
</div>
</section>
<section className="shell mt-8" aria-labelledby="tabela-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="tabela-titulo" className="text-base font-semibold text-ink">Especificações</h2>
<label className="flex min-h-11 cursor-pointer items-center gap-2.5 text-sm font-medium text-ink-soft">
<input
type="checkbox"
checked={soDiferencas}
onChange={(e) => setSoDiferencas(e.target.checked)}
className="h-5 w-5 cursor-pointer accent-[var(--accent)]"
/>
Mostrar só as diferenças
</label>
</div>
<div className="panel mt-3 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full min-w-[30rem] border-collapse text-sm">
<caption className="sr-only">Comparação das séries {selectedSeries.join(", ")}</caption>
<thead>
<tr className="border-b border-line bg-surface-2">
<th scope="col" className="sticky left-0 z-20 w-28 bg-surface-2 px-4 py-4 text-left font-semibold text-muted sm:w-52 sm:px-6">
Especificação
</th>
{selectedSeries.map((seriesKey) => (
<th key={seriesKey} scope="col" className="min-w-40 px-4 py-4 text-left sm:px-6">
<Link href={`/series/${seriesKey}`} className="inline-flex min-h-11 items-center gap-1 font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
<ArrowUpRight className="h-4 w-4 text-muted" aria-hidden="true" />
</Link>
</th>
))}
</tr>
</thead>
<tbody>
{compareFields.map(({ category, fields }) => {
const visiveis = soDiferencas ? fields.filter(({ key }) => diferem(key)) : fields;
if (soDiferencas && visiveis.length === 0) return null;
const isCollapsed = collapsedCategories[category] && !soDiferencas;
return (
<Fragment key={category}>
<tr className="border-y border-line bg-surface-2/60">
<th scope="rowgroup" colSpan={selectedSeries.length + 1} className="p-0 text-left">
<button
type="button"
onClick={() => toggleCategory(category)}
aria-expanded={!isCollapsed}
className="flex min-h-12 w-full cursor-pointer items-center justify-between gap-3 px-4 py-3 text-left font-semibold text-ink sm:px-6"
>
<span className="sticky left-4 sm:left-6">{category}</span>
<ChevronDown className={`h-4 w-4 shrink-0 text-muted transition-transform ${isCollapsed ? "" : "rotate-180"}`} aria-hidden="true" />
</button>
</th>
</tr>
{!isCollapsed &&
visiveis.map(({ key, label }) => (
<tr key={key} className="border-b border-line last:border-b-0 hover:bg-surface-2/50">
<th scope="row" className="sticky left-0 z-10 bg-surface px-4 py-3.5 text-left align-top font-medium text-muted sm:px-6">
{label}
</th>
{selectedSeries.map((seriesKey) => (
<td key={seriesKey} className="px-4 py-3.5 align-top sm:px-6">
{renderValue(valorDe(seriesData[seriesKey], key))}
</td>
))}
</tr>
))}
</Fragment>
);
})}
</tbody>
</table>
</div>
</div>
</section>
<section className="shell section" aria-labelledby="docs-titulo">
<h2 id="docs-titulo" className="section-title">Documentação oficial</h2>
<div className="mt-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
{selectedSeries.map((seriesKey) => {
const seriesItem = seriesData[seriesKey];
return (
<div key={seriesKey} className="card flex flex-col justify-between gap-5 p-5">
<Link href={`/series/${seriesKey}`} className="inline-flex min-h-11 items-center font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
</Link>
{seriesItem.datasheet ? (
<a href={seriesItem.datasheet} target="_blank" rel="noopener noreferrer" className="btn btn-ghost btn-sm">
Datasheet oficial
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> (abre em nova aba)</span>
</a>
) : (
<span className="text-sm text-muted">Datasheet ainda não publicado</span>
)}
</div>
);
})}
</div>
<div className="panel mt-10 flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">Quer testar na bancada?</h2>
<p className="mt-3 text-base text-muted">Veja as placas de desenvolvimento com pinagem, periféricos e link para a loja.</p>
</div>
<Link href="/catalogo" className="btn btn-primary shrink-0">
Ver catálogo de placas
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
</main>
<Footer />
</div>
);
}
-74
View File
@@ -1,74 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "ESP Component Registry & IDF Component Manager · ESPDocs",
descricao: "Catálogo oficial e interativo do ESP Component Registry: drivers de displays, LVGL, reconhecimento de voz ESP-SR, RainMaker, BSPs e gerador de idf_component.yml.",
caminho: "/componentes",
keywords: [
"ESP Component Registry",
"IDF Component Manager",
"idf_component.yml",
"idf.py add-dependency",
"componentes ESP32",
"espressif esp_lvgl_port",
"espressif esp_rainmaker",
"espressif esp-sr",
"bibliotecas ESP-IDF",
],
});
const faqs = [
{
pergunta: "O que é o ESP Component Registry e o IDF Component Manager?",
resposta: "O ESP Component Registry (components.espressif.com) é o repositório oficial de pacotes modulares da Espressif. O IDF Component Manager é a ferramenta integrada ao ESP-IDF (a partir do v4.4 e padrão no v5.x+) que baixa, compila e resolve versões de dependências automaticamente a partir do manifesto idf_component.yml.",
},
{
pergunta: "Como adicionar um componente ao meu projeto ESP-IDF?",
resposta: "Você pode executar o comando 'idf.py add-dependency \"namespace/componente^versao\"' no terminal do projeto (por exemplo: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") ou editar diretamente o arquivo main/idf_component.yml.",
},
{
pergunta: "Qual a diferença entre usar o Component Registry e git submodules?",
resposta: "O Component Registry elimina a complexidade de gerenciar submódulos Git pesados e versões manuais. Ele oferece versionamento semântico (^ e ~), resolução automática de dependências transitivas e compilação modular sob demanda.",
},
{
pergunta: "Posso criar e publicar meus próprios componentes?",
resposta: "Sim, qualquer desenvolvedor ou empresa pode publicar componentes públicos ou privados no ESP Component Registry utilizando a ferramenta oficial Compote CLI (pip install idf-component-manager).",
},
];
export default function ComponentesLayout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "ESP Component Registry", caminho: "/componentes" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Hub do ESP Component Registry & Construtor de Manifesto",
descricao: "Catálogo curado e gerador de manifesto idf_component.yml para componentes modulares do ESP-IDF.",
caminho: "/componentes",
})
),
}}
/>
{children}
</>
);
}
-419
View File
@@ -1,419 +0,0 @@
"use client";
import { useState, useMemo } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import SectionHead from "@/components/SectionHead";
import {
CATEGORIAS_COMPONENTES,
COMPONENTES_REGISTRY,
GUIA_COMPONENT_MANAGER
} from "@/lib/componentRegistryData";
import {
ArrowUpRight,
Box,
Brain,
Check,
CircuitBoard,
Cloud,
Copy,
Cpu,
Download,
HelpCircle,
Home,
Layers,
Monitor,
Plus,
Search,
ShieldCheck,
Terminal,
Trash2,
Wrench,
X,
} from "lucide-react";
const ICONES_CATEGORIA = {
ui_display: Monitor,
cloud_conectividade: Cloud,
audio_voz_ia: Brain,
smart_home_mesh: Home,
drivers_perifericos: Cpu,
bsp_placas: CircuitBoard,
sistema_utilitarios: Wrench,
};
export default function ComponentRegistryPage() {
const [busca, setBusca] = useState("");
const [categoriaAtiva, setCategoriaAtiva] = useState("todos");
const [chipFiltro, setChipFiltro] = useState("todos");
const [copiadoId, setCopiadoId] = useState(null);
const [manifestoCopiado, setManifestoCopiado] = useState(false);
// Componentes selecionados no construtor de idf_component.yml
const [componentesSelecionados, setComponentesSelecionados] = useState([
"espressif-esp_lvgl_port",
"espressif-led_indicator"
]);
// Lista de chips únicos para filtro
const chipsDisponiveis = ["todos", "ESP32", "ESP32-S3", "ESP32-C6", "ESP32-P4", "ESP32-H2", "ESP32-C3"];
// Filtragem dos componentes
const componentesFiltrados = useMemo(() => {
return COMPONENTES_REGISTRY.filter((comp) => {
const matchCategoria = categoriaAtiva === "todos" || comp.categoria === categoriaAtiva;
const matchChip = chipFiltro === "todos" || (comp.chips && comp.chips.includes(chipFiltro));
const matchBusca =
busca.trim() === "" ||
comp.name.toLowerCase().includes(busca.toLowerCase()) ||
comp.namespace.toLowerCase().includes(busca.toLowerCase()) ||
comp.titulo.toLowerCase().includes(busca.toLowerCase()) ||
comp.descricao.toLowerCase().includes(busca.toLowerCase()) ||
comp.tags.some((t) => t.toLowerCase().includes(busca.toLowerCase()));
return matchCategoria && matchChip && matchBusca;
});
}, [busca, categoriaAtiva, chipFiltro]);
// Manipuladores de cópia
const copiarComando = (id, comando) => {
navigator.clipboard.writeText(comando);
setCopiadoId(id);
setTimeout(() => setCopiadoId(null), 2000);
};
const toggleSelecaoManifesto = (id) => {
setComponentesSelecionados((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
);
};
// Geração dinâmica do manifesto YAML
const manifestoYaml = useMemo(() => {
const selecionados = COMPONENTES_REGISTRY.filter((c) =>
componentesSelecionados.includes(c.id)
);
if (selecionados.length === 0) {
return `# Nenhum componente selecionado.\n# Clique em "+ Adicionar ao Manifesto" nos cards abaixo.`;
}
let yaml = `# main/idf_component.yml\n# Gerado via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/componentes)\n\ndependencies:\n`;
selecionados.forEach((c) => {
yaml += ` ${c.namespace}/${c.name}: "${c.versao}"\n`;
});
return yaml;
}, [componentesSelecionados]);
const copiarManifesto = () => {
navigator.clipboard.writeText(manifestoYaml);
setManifestoCopiado(true);
setTimeout(() => setManifestoCopiado(false), 2000);
};
const baixarManifesto = () => {
const blob = new Blob([manifestoYaml], { type: "text/yaml;charset=utf-8" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "idf_component.yml";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const limparFiltros = () => {
setBusca("");
setCategoriaAtiva("todos");
setChipFiltro("todos");
};
const totalFiltros = (busca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (chipFiltro !== "todos" ? 1 : 0);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Component Registry" }]}
icon={Box}
label="ESP-IDF Component Manager"
title="ESP Component Registry"
lede="O catálogo oficial de pacotes reutilizáveis da Espressif para o ESP-IDF. Escolha drivers, voz e pilhas industriais, copie o comando e gere o manifesto do projeto."
>
<a href="https://components.espressif.com" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
Abrir o registro oficial
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> (abre em nova aba)</span>
</a>
<a href="#manifesto-builder" className="btn btn-ghost">
Gerar idf_component.yml
</a>
</PageHero>
<section className="shell pt-10 sm:pt-12" aria-label="Busca e filtros">
<div className="panel p-5 sm:p-6">
<div className="relative">
<label htmlFor="busca-componente" className="sr-only">Buscar por nome, namespace ou tag</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-componente"
type="search"
value={busca}
onChange={(e) => setBusca(e.target.value)}
placeholder="Buscar por nome, namespace ou tag"
autoComplete="off"
className="field pl-12 pr-4 text-base"
/>
</div>
<div className="mt-5">
<h2 className="text-sm font-semibold text-ink">Categoria</h2>
<div className="mt-3 flex flex-wrap gap-2">
{CATEGORIAS_COMPONENTES.map((cat) => {
const Icone = ICONES_CATEGORIA[cat.id] ?? Layers;
const contagem = cat.id === "todos" ? COMPONENTES_REGISTRY.length : COMPONENTES_REGISTRY.filter((c) => c.categoria === cat.id).length;
return (
<button key={cat.id} type="button" onClick={() => setCategoriaAtiva(cat.id)} aria-pressed={categoriaAtiva === cat.id} className="chip-btn">
<Icone className="h-4 w-4" aria-hidden="true" />
{cat.id === "todos" ? "Todos" : cat.nome.replace(/\s*\(.*\)/, "").split(",")[0].split(" &")[0]}
<span className="tabular-nums opacity-80">{contagem}</span>
</button>
);
})}
</div>
</div>
<div className="mt-5 border-t border-line pt-5">
<h2 className="text-sm font-semibold text-ink">Chip compatível</h2>
<div className="mt-3 flex flex-wrap gap-2">
{chipsDisponiveis.map((chip) => (
<button key={chip} type="button" onClick={() => setChipFiltro(chip)} aria-pressed={chipFiltro === chip} className="chip-btn">
{chip === "todos" ? "Todos" : chip}
</button>
))}
</div>
</div>
</div>
</section>
<section className="shell section pt-8 sm:pt-10" aria-labelledby="lista-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="lista-titulo" role="status" aria-live="polite" className="text-base font-semibold text-ink">
{componentesFiltrados.length} {componentesFiltrados.length === 1 ? "componente" : "componentes"}
</h2>
<div className="flex flex-wrap items-center gap-x-5 gap-y-1">
{totalFiltros > 0 && (
<button type="button" onClick={limparFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<X className="h-4 w-4" aria-hidden="true" />
Limpar filtros
</button>
)}
<a href="#manifesto-builder" className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
Manifesto: {componentesSelecionados.length} {componentesSelecionados.length === 1 ? "componente" : "componentes"}
</a>
</div>
</div>
{componentesFiltrados.length === 0 ? (
<div className="card mt-6 px-6 py-14 text-center">
<Box className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">Nenhum componente encontrado</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">Busque por um termo mais geral ou volte para todas as categorias.</p>
<button type="button" onClick={limparFiltros} className="btn btn-primary mt-6">Limpar filtros</button>
</div>
) : (
<div className="mt-6 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{componentesFiltrados.map((comp) => {
const selecionado = componentesSelecionados.includes(comp.id);
const cliCmd = `idf.py add-dependency "${comp.namespace}/${comp.name}${comp.versao}"`;
const foiCopiado = copiadoId === comp.id;
return (
<article key={comp.id} className={`card flex flex-col overflow-hidden ${selecionado ? "border-accent ring-2 ring-accent/20" : ""}`}>
<div className="flex-1 p-5 sm:p-6">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="flex flex-wrap items-center gap-2 text-xs text-muted">
{comp.namespace}/
{comp.oficial && (
<span className="chip chip-accent px-2 py-0">
<ShieldCheck className="h-3 w-3" aria-hidden="true" />
Oficial
</span>
)}
</p>
<h3 className="mt-1 break-words font-display text-xl font-semibold tracking-[-0.03em] text-ink">{comp.name}</h3>
<p className="mt-0.5 text-sm font-medium text-accent">{comp.titulo}</p>
</div>
<span className="shrink-0 rounded-md border border-line bg-surface-2 px-2 py-1 font-mono text-xs text-ink-soft">{comp.versao}</span>
</div>
<p className="mt-3 line-clamp-3 text-sm leading-relaxed text-muted">{comp.descricao}</p>
<ul className="mt-4 flex flex-wrap gap-1.5">
{comp.tags.map((tag) => (
<li key={tag} className="chip">{tag}</li>
))}
</ul>
</div>
<div className="border-t border-line bg-surface-2/60 p-5 sm:px-6">
<button
type="button"
onClick={() => copiarComando(comp.id, cliCmd)}
className="code-panel flex w-full min-h-11 items-center justify-between gap-3 rounded-lg px-3 py-2 text-left font-mono text-xs transition-colors hover:border-white/30"
aria-label={`Copiar comando para adicionar ${comp.name}`}
>
<span className="truncate text-[#e9eef4]">{cliCmd}</span>
{foiCopiado ? <Check className="h-4 w-4 shrink-0 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4 shrink-0 text-[#a6afbd]" aria-hidden="true" />}
</button>
<p role="status" className="sr-only">{foiCopiado ? "Comando copiado" : ""}</p>
<p className="mt-3 text-xs text-muted">
<span className="font-medium text-ink-soft">Chips: </span>
{comp.chips.join(", ")}
</p>
</div>
<div className="flex items-center justify-between gap-2 border-t border-line p-4 sm:px-6">
<button
type="button"
onClick={() => toggleSelecaoManifesto(comp.id)}
aria-pressed={selecionado}
className={`btn btn-sm ${selecionado ? "btn-primary" : "btn-ghost"}`}
>
{selecionado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Plus className="h-4 w-4" aria-hidden="true" />}
{selecionado ? "No manifesto" : "Adicionar ao manifesto"}
</button>
<a
href={comp.urlRegistry}
target="_blank"
rel="noopener noreferrer"
className="btn-icon inline-flex h-11 w-11 items-center justify-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-accent"
aria-label={`Abrir ${comp.name} no registro oficial (nova aba)`}
>
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</div>
</article>
);
})}
</div>
)}
</section>
<section id="manifesto-builder" className="shell scroll-mt-28 pb-16" aria-labelledby="manifesto-titulo">
<div className="panel p-6 sm:p-9">
<div className="flex flex-col justify-between gap-5 md:flex-row md:items-end">
<div className="max-w-2xl">
<p className="eyebrow">Gerador de manifesto</p>
<h2 id="manifesto-titulo" className="section-title mt-3">Seu idf_component.yml</h2>
<p className="mt-3 text-sm leading-relaxed text-muted">
Salve o arquivo na pasta <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> do projeto e o
ESP-IDF baixa todas as bibliotecas na compilação.
</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<button type="button" onClick={copiarManifesto} className="btn btn-primary btn-sm">
{manifestoCopiado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
<span role="status">{manifestoCopiado ? "Copiado" : "Copiar YAML"}</span>
</button>
<button type="button" onClick={baixarManifesto} className="btn btn-ghost btn-sm">
<Download className="h-4 w-4" aria-hidden="true" />
Baixar .yml
</button>
{componentesSelecionados.length > 0 && (
<button type="button" onClick={() => setComponentesSelecionados([])} className="btn btn-ghost btn-sm">
<Trash2 className="h-4 w-4" aria-hidden="true" />
Limpar
</button>
)}
</div>
</div>
<div className="code-panel mt-6">
<pre tabIndex={0} aria-label="Conteúdo do idf_component.yml" className="!text-sm"><code className="text-[#e9eef4]">{manifestoYaml}</code></pre>
</div>
{componentesSelecionados.length > 0 && (
<ul className="mt-5 flex flex-wrap items-center gap-2" aria-label="Componentes incluídos">
{componentesSelecionados.map((id) => {
const c = COMPONENTES_REGISTRY.find((item) => item.id === id);
if (!c) return null;
return (
<li key={id} className="chip chip-accent gap-1 pr-1">
{c.name}
<button
type="button"
onClick={() => toggleSelecaoManifesto(id)}
className="-my-2 grid h-11 w-11 place-items-center rounded-full hover:bg-accent/15"
aria-label={`Remover ${c.name} do manifesto`}
>
<X className="h-3.5 w-3.5" aria-hidden="true" />
</button>
</li>
);
})}
</ul>
)}
</div>
</section>
<section className="shell section border-t border-line pt-14" aria-labelledby="guia-titulo">
<SectionHead id="guia-titulo" eyebrow="Guia rápido" title={GUIA_COMPONENT_MANAGER.titulo} lede={GUIA_COMPONENT_MANAGER.resumo} />
<ul className="mt-8 grid gap-3 md:grid-cols-2 lg:grid-cols-4">
{GUIA_COMPONENT_MANAGER.vantagens.map((v) => (
<li key={v.titulo} className="card p-5">
<h3 className="font-semibold text-ink">{v.titulo}</h3>
<p className="mt-2 text-sm leading-relaxed text-muted">{v.descricao}</p>
</li>
))}
</ul>
<h3 className="mt-12 flex items-center gap-2 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
<Terminal className="h-5 w-5 text-accent" aria-hidden="true" />
Comandos essenciais
</h3>
<ul className="mt-4 space-y-3">
{GUIA_COMPONENT_MANAGER.comandosCli.map((cmd, i) => (
<li key={cmd.exemplo} className="code-panel flex flex-col justify-between gap-3 p-4 md:flex-row md:items-center">
<div className="min-w-0">
<code className="block break-all font-mono text-sm text-[#5eead4]">$ {cmd.exemplo}</code>
<p className="mt-1 text-sm text-[#a6afbd]">{cmd.explicacao}</p>
</div>
<button
type="button"
onClick={() => copiarComando(`cmd-${i}`, cmd.exemplo)}
className="inline-flex min-h-11 shrink-0 items-center gap-1.5 self-start rounded-full border border-white/15 px-4 text-sm font-medium text-[#e9eef4] transition-colors hover:bg-white/10 md:self-auto"
>
{copiadoId === `cmd-${i}` ? <Check className="h-4 w-4 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `cmd-${i}` ? "Copiado" : "Copiar"}
</button>
</li>
))}
</ul>
<div className="callout mt-8">
<h3 className="flex items-center gap-2 font-semibold text-ink">
<HelpCircle className="h-4 w-4 text-accent" aria-hidden="true" />
Versionamento semântico no ESP-IDF
</h3>
<ul className="mt-2 list-disc space-y-1.5 pl-5">
<li><code>^1.2.0</code>: aceita atualizações menores e correções (1.2.1, 1.3.0), mas bloqueia mudanças grandes de API (2.0.0). <strong>Recomendado.</strong></li>
<li><code>~1.2.0</code>: aceita só correções de bugs (1.2.1, 1.2.5).</li>
<li><code>1.2.0</code>: trava na versão exata.</li>
<li><code>*</code>: aceita qualquer versão. Evite em produção.</li>
</ul>
</div>
</section>
</main>
<Footer />
</div>
);
}
-75
View File
@@ -1,75 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Diagnóstico de Erros Comuns no ESP32: Guia Profissional",
descricao: "Guia técnico definitivo para identificar e resolver Brownout, Guru Meditation, Task Watchdog, Stack Overflow, vazamento de memória e falhas de boot no ESP32 (Arduino e ESP-IDF).",
caminho: "/diagnostico",
keywords: [
"erros comuns ESP32",
"brownout detector was triggered",
"guru meditation error",
"task watchdog got triggered",
"stack canary watchpoint triggered",
"como debugar ESP32",
"ESP32 reiniciando em loop",
"failed to connect to esp32",
],
});
const faqs = [
{
pergunta: "O que causa o erro 'Brownout detector was triggered' no ESP32?",
resposta: "Ocorre quando a tensão no pino 3V3 cai abaixo de 2.8V ~ 2.43V devido a picos rápidos de corrente do rádio Wi-Fi/BLE (superando 500mA), cabos USB finos ou regulador LDO inadequado. A solução de engenharia envolve adicionar capacitores Low-ESR de 10µF a 100µF próximos ao VCC e usar LDOs robustos de 600mA+.",
},
{
pergunta: "Como resolver o 'Guru Meditation Error (LoadProhibited)'?",
resposta: "LoadProhibited indica tentativa de acessar um ponteiro nulo (NULL) ou inválido na memória. A solução consiste em usar o Espressif Exception Decoder ou addr2line para localizar a linha exata no código e implementar validações defensivas como if (ponteiro != NULL).",
},
{
pergunta: "Por que o Task Watchdog Timer (TWDT) dispara no FreeRTOS?",
resposta: "O TWDT dispara quando uma tarefa de prioridade maior monopoliza a CPU em um loop bloqueante (ex: while(1) sem vTaskDelay), impedindo a tarefa IDLE de alimentar o watchdog do sistema operacional.",
},
{
pergunta: "Por que conexões HTTPS e TLS falham com código -0x2700 no ESP32?",
resposta: "Porque ao ligar, o ESP32 inicia o relógio interno no ano de 1970. O validador de certificados TLS considera o certificado do servidor inválido por estar no 'futuro'. Sincronizar o relógio via SNTP (configTime) antes da conexão resolve o problema.",
},
];
export default function DiagnosticoLayout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Diagnóstico & Erros Comuns", caminho: "/diagnostico" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.perguntas(faqs)
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Guia de Diagnóstico e Erros no ESP32",
descricao: "Ferramenta e guia técnico de análise de falhas, pânicos de CPU e decodificação de logs no ESP32.",
caminho: "/diagnostico",
})
),
}}
/>
{children}
</>
);
}
-469
View File
@@ -1,469 +0,0 @@
"use client";
import { useState, useMemo, useRef } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import {
categoriasDiagnostico,
sintomasRapidos,
errosCatalogo,
regrasDecodificadorLog,
} from "@/lib/diagnosticoData";
import {
Activity,
AlertTriangle,
Check,
CheckCircle2,
ChevronDown,
Copy,
Cpu,
ExternalLink,
HelpCircle,
Layers,
LayoutGrid,
RotateCcw,
Search,
ShieldAlert,
Terminal,
Wifi,
Wrench,
X,
XCircle,
Zap,
} from "lucide-react";
/** Os rótulos dos sintomas vêm com emoji nos dados; a interface usa só texto e ícones. */
const semEmoji = (texto) => texto.replace(/^[\p{Extended_Pictographic}\uFE0F\s]+/u, "");
const ICONES = { Zap, Cpu, Layers, Activity, Terminal, Wifi };
const EXEMPLOS_LOG = [
["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"],
["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"],
["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"],
["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"],
];
const GRAVIDADE = {
"Crítica": "text-danger",
Alta: "text-gold",
};
const CHECKLISTS = [
{
icon: Zap,
titulo: "Hardware e alimentação",
itens: [
"Capacitor de 10 µF a 100 µF de baixo ESR no VCC, mais um cerâmico de 100 nF junto ao chip.",
"LDO dimensionado para picos de 600 mA a 1 A, com folga térmica.",
"Nenhum periférico forçando nível lógico nos pinos de strapping durante o boot.",
"Capacitor de 10 µF ou 1 µF no pino EN (RST) para auto-reset estável na gravação.",
],
},
{
icon: Layers,
titulo: "Firmware e FreeRTOS",
itens: [
"Toda tarefa FreeRTOS cede a CPU com vTaskDelay, filas ou semáforos.",
"Toda ISR marcada com IRAM_ATTR e sem chamadas bloqueantes.",
"Sem uso contínuo de String do Arduino em laços, para evitar fragmentação do heap.",
"Horário sincronizado por SNTP antes de abrir conexões TLS/HTTPS.",
],
},
];
export default function DiagnosticoPage() {
const [termoBusca, setTermoBusca] = useState("");
const [categoriaAtiva, setCategoriaAtiva] = useState("todos");
const [sintomaAtivo, setSintomaAtivo] = useState(null);
const [cardAberto, setCardAberto] = useState(null);
const [linguagemCodigo, setLinguagemCodigo] = useState({}); // { [id]: 'arduino' | 'espidf' }
const [copiadoId, setCopiadoId] = useState(null);
const searchInputRef = useRef(null);
// Estado do Analisador de Logs
const [logInput, setLogInput] = useState("");
const [resultadoLog, setResultadoLog] = useState(null);
// Função de Análise do Log
const analisarLog = (texto) => {
setLogInput(texto);
if (!texto || texto.trim() === "") {
setResultadoLog(null);
return;
}
for (const regra of regrasDecodificadorLog) {
if (regra.padrao.test(texto)) {
setResultadoLog(regra);
return;
}
}
setResultadoLog({
titulo: "Padrão de erro não categorizado automaticamente",
tipo: "Desconhecido",
explicacao:
"Não identificamos uma assinatura clássica de Guru Meditation ou Brownout neste trecho. Verifique se a taxa de baud rate (ex: 115200) está correta e se o cabeçalho 'rst:' ou 'panic' está presente.",
acaoRecomendada:
"Procure por palavras-chave como 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' ou 'panic' no console serial.",
});
};
const copiarParaClipboard = (texto, id) => {
navigator.clipboard.writeText(texto);
setCopiadoId(id);
setTimeout(() => setCopiadoId(null), 2000);
};
// Filtragem dos erros
const errosFiltrados = useMemo(() => {
const termo = termoBusca.toLowerCase().trim();
return errosCatalogo.filter((erro) => {
const matchCategoria =
categoriaAtiva === "todos" || erro.categoria === categoriaAtiva;
const matchSintoma =
!sintomaAtivo || erro.sintomas.includes(sintomaAtivo);
const matchBusca =
!termo ||
erro.titulo.toLowerCase().includes(termo) ||
erro.resumo.toLowerCase().includes(termo) ||
erro.causaRaiz.toLowerCase().includes(termo) ||
erro.logSerial.toLowerCase().includes(termo);
return matchCategoria && matchSintoma && matchBusca;
});
}, [categoriaAtiva, sintomaAtivo, termoBusca]);
const temFiltroAtivo =
termoBusca.trim() !== "" ||
categoriaAtiva !== "todos" ||
sintomaAtivo !== null;
const limparTodosFiltros = () => {
setTermoBusca("");
setCategoriaAtiva("todos");
setSintomaAtivo(null);
searchInputRef.current?.focus();
};
const toggleCard = (id) => {
setCardAberto((prev) => (prev === id ? null : id));
};
const setLang = (id, lang) => {
setLinguagemCodigo((prev) => ({ ...prev, [id]: lang }));
};
const totalFiltros = (termoBusca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (sintomaAtivo ? 1 : 0);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Diagnóstico" }]}
icon={AlertTriangle}
label="Depuração de firmware"
title="Diagnóstico de falhas do ESP32"
lede="Entenda a causa de Brownout, Guru Meditation, Watchdog e Stack Overflow, e aplique a correção de engenharia, não o remendo."
>
<a
href="https://cienciaembarcada.com.br/publicacoes/esp32-5-erros-comuns-e-como-resolve-los-profissionalmente/"
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong"
>
Baseado no artigo do Ciência Embarcada
<ExternalLink className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> (abre em nova aba)</span>
</a>
</PageHero>
<section className="shell pt-10 sm:pt-12" aria-labelledby="decodificador-titulo">
<div className="panel p-5 sm:p-8">
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-end">
<div className="max-w-xl">
<h2 id="decodificador-titulo" className="section-title">Cole o log e veja a causa</h2>
<p className="mt-2 text-sm text-muted">Copie o trecho do monitor serial. O diagnóstico aparece na hora.</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<span className="text-sm text-muted">Testar com</span>
{EXEMPLOS_LOG.map(([rotulo, texto]) => (
<button key={rotulo} type="button" onClick={() => analisarLog(texto)} className="chip-btn">
{rotulo}
</button>
))}
</div>
</div>
<div className="relative mt-5">
<label htmlFor="log-serial" className="sr-only">Log do monitor serial</label>
<textarea
id="log-serial"
rows={4}
value={logInput}
onChange={(e) => analisarLog(e.target.value)}
placeholder="Cole o log do monitor serial aqui"
spellCheck={false}
className="code-panel field !min-h-32 w-full resize-y !rounded-xl !border-white/10 !bg-[var(--code-bg)] p-4 font-mono text-sm !text-[#e9eef4] placeholder:!text-[#a6afbd]"
/>
{logInput && (
<button type="button" onClick={() => analisarLog("")} className="absolute right-3 top-3 inline-flex min-h-11 items-center gap-1 rounded-full border border-white/15 px-3 text-xs font-medium text-[#e9eef4] hover:bg-white/10">
<X className="h-3.5 w-3.5" aria-hidden="true" />
Limpar
</button>
)}
</div>
<div role="status" aria-live="polite">
{resultadoLog && (
<div className="callout callout-warn mt-4 flex items-start gap-3">
<ShieldAlert className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
<div className="min-w-0 space-y-2">
<div className="flex flex-wrap items-center gap-2">
<h3 className="font-semibold text-ink">{resultadoLog.titulo}</h3>
<span className="chip">{resultadoLog.tipo}</span>
</div>
<p><strong className="font-semibold text-ink">Causa provável:</strong> {resultadoLog.explicacao}</p>
<p><strong className="font-semibold text-ink">O que fazer:</strong> {resultadoLog.acaoRecomendada}</p>
</div>
</div>
)}
</div>
</div>
</section>
<section className="shell section pt-12 sm:pt-14" aria-labelledby="catalogo-titulo">
<h2 id="catalogo-titulo" className="section-title">Catálogo de falhas</h2>
<div className="panel mt-6 p-5 sm:p-6">
<div className="relative">
<label htmlFor="busca-erro" className="sr-only">Buscar por erro, sintoma ou mensagem serial</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-erro"
ref={searchInputRef}
type="search"
value={termoBusca}
onChange={(e) => setTermoBusca(e.target.value)}
placeholder="Buscar erro, sintoma ou mensagem"
autoComplete="off"
className="field pl-12 pr-4 text-base"
/>
</div>
<div className="mt-5">
<h3 className="text-sm font-semibold text-ink">Sintoma</h3>
<div className="mt-3 flex flex-wrap gap-2">
{sintomasRapidos.map((sintoma) => (
<button key={sintoma.id} type="button" onClick={() => setSintomaAtivo(sintomaAtivo === sintoma.id ? null : sintoma.id)} aria-pressed={sintomaAtivo === sintoma.id} className="chip-btn">
{semEmoji(sintoma.rotulo)}
</button>
))}
</div>
</div>
<div className="mt-5 border-t border-line pt-5">
<h3 className="text-sm font-semibold text-ink">Área</h3>
<div className="mt-3 flex flex-wrap gap-2">
<button type="button" onClick={() => setCategoriaAtiva("todos")} aria-pressed={categoriaAtiva === "todos"} className="chip-btn">
<LayoutGrid className="h-4 w-4" aria-hidden="true" />
Todas
<span className="tabular-nums opacity-80">{errosCatalogo.length}</span>
</button>
{categoriasDiagnostico.map((cat) => {
const Icone = ICONES[cat.icone] ?? AlertTriangle;
const total = errosCatalogo.filter((e) => e.categoria === cat.id).length;
return (
<button key={cat.id} type="button" onClick={() => setCategoriaAtiva(cat.id)} aria-pressed={categoriaAtiva === cat.id} className="chip-btn">
<Icone className="h-4 w-4" aria-hidden="true" />
{cat.nome.split(/ &|,/)[0]}
<span className="tabular-nums opacity-80">{total}</span>
</button>
);
})}
</div>
</div>
</div>
<div className="mt-6 flex flex-wrap items-center justify-between gap-3">
<p role="status" aria-live="polite" className="text-sm font-semibold text-ink">
{errosFiltrados.length} {errosFiltrados.length === 1 ? "falha" : "falhas"}
{totalFiltros > 0 && <span className="font-normal text-muted"> com os filtros atuais</span>}
</p>
{temFiltroAtivo && (
<button type="button" onClick={limparTodosFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
Redefinir filtros
</button>
)}
</div>
<div className="mt-3 space-y-3">
{errosFiltrados.length === 0 ? (
<div className="card px-6 py-14 text-center">
<HelpCircle className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">Nenhuma falha com esses filtros</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">Busque por um termo mais geral ou remova o sintoma e a área selecionados.</p>
<button type="button" onClick={limparTodosFiltros} className="btn btn-primary mt-6">Limpar filtros</button>
</div>
) : (
errosFiltrados.map((erro) => {
const estaAberto = cardAberto === erro.id;
const lang = linguagemCodigo[erro.id] || "arduino";
const codigoAtual =
lang === "arduino" ? erro.codigoArduino : lang === "espidf" ? erro.codigoEspIdf : erro.codigoMicroPython || "# Exemplo não aplicável";
const catInfo = categoriasDiagnostico.find((c) => c.id === erro.categoria);
const IconeCat = ICONES[catInfo?.icone] ?? AlertTriangle;
return (
<article key={erro.id} id={erro.id} className={`card scroll-mt-28 overflow-hidden ${estaAberto ? "border-line-strong" : ""}`}>
<h3>
<button
type="button"
onClick={() => toggleCard(erro.id)}
aria-expanded={estaAberto}
aria-controls={`detalhe-${erro.id}`}
className="flex w-full cursor-pointer items-start justify-between gap-4 p-5 text-left sm:p-6"
>
<span className="min-w-0">
<span className="flex flex-wrap items-center gap-2">
<span className="chip">
<IconeCat className="h-3.5 w-3.5 text-accent" aria-hidden="true" />
{catInfo?.nome}
</span>
<span className={`chip ${GRAVIDADE[erro.gravidade] ?? "text-accent"}`}>Gravidade {erro.gravidade.toLowerCase()}</span>
</span>
<span className="mt-3 block font-display text-xl font-semibold tracking-[-0.03em] text-ink">{erro.titulo}</span>
<span className="mt-1.5 block text-sm font-normal leading-relaxed text-muted">{erro.resumo}</span>
</span>
<span className="mt-1 grid h-9 w-9 shrink-0 place-items-center rounded-full bg-surface-2 text-muted">
<ChevronDown className={`h-4 w-4 transition-transform ${estaAberto ? "rotate-180" : ""}`} aria-hidden="true" />
</span>
</button>
</h3>
{estaAberto && (
<div id={`detalhe-${erro.id}`} className="space-y-6 border-t border-line p-5 sm:p-6">
<div>
<div className="flex items-center justify-between gap-3">
<h4 className="flex items-center gap-2 text-sm font-semibold text-ink">
<Terminal className="h-4 w-4 text-accent" aria-hidden="true" />
Como aparece no monitor serial
</h4>
<button type="button" onClick={() => copiarParaClipboard(erro.logSerial, `log-${erro.id}`)} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
{copiadoId === `log-${erro.id}` ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `log-${erro.id}` ? "Copiado" : "Copiar log"}
</button>
</div>
<div className="code-panel mt-1">
<pre tabIndex={0}><code className="text-[#e9eef4]">{erro.logSerial}</code></pre>
</div>
</div>
<div>
<h4 className="flex items-center gap-2 text-sm font-semibold text-ink">
<Cpu className="h-4 w-4 text-accent" aria-hidden="true" />
Causa raiz
</h4>
<p className="callout mt-2">{erro.causaRaiz}</p>
</div>
<div className="grid gap-4 md:grid-cols-2">
<div className="callout callout-danger">
<p className="flex items-center gap-2 font-semibold text-ink">
<XCircle className="h-4 w-4 shrink-0 text-danger" aria-hidden="true" />
O remendo comum
</p>
<p className="mt-2 font-medium text-ink">{erro.gambiarra.titulo}</p>
<p className="mt-1">{erro.gambiarra.descricao}</p>
<p className="mt-2"><strong className="font-semibold text-danger">Consequência:</strong> {erro.gambiarra.consequencia}</p>
</div>
<div className="callout callout-ok">
<p className="flex items-center gap-2 font-semibold text-ink">
<CheckCircle2 className="h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
A solução de engenharia
</p>
<p className="mt-2 font-medium text-ink">{erro.solucaoEngenharia.titulo}</p>
<ul className="mt-2 space-y-1.5">
{erro.solucaoEngenharia.passos.map((passo) => (
<li key={passo} className="flex items-start gap-2">
<Check className="mt-1 h-3.5 w-3.5 shrink-0 text-ok" aria-hidden="true" />
{passo}
</li>
))}
</ul>
</div>
</div>
<div>
<div className="flex flex-wrap items-center justify-between gap-3">
<div role="group" aria-label="Linguagem do exemplo" className="flex flex-wrap gap-2">
{[
["arduino", "Arduino C++"],
["espidf", "ESP-IDF (C)"],
["micropython", "MicroPython"],
].map(([id, rotulo]) => (
<button key={id} type="button" onClick={() => setLang(erro.id, id)} aria-pressed={lang === id} className="chip-btn">
{rotulo}
</button>
))}
</div>
<button type="button" onClick={() => copiarParaClipboard(codigoAtual, `code-${erro.id}`)} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
{copiadoId === `code-${erro.id}` ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
{copiadoId === `code-${erro.id}` ? "Copiado" : "Copiar código"}
</button>
</div>
<div className="code-panel mt-3">
<pre tabIndex={0}><code className="text-[#e9eef4]">{codigoAtual}</code></pre>
</div>
</div>
<div className="callout callout-warn flex items-start gap-3">
<Wrench className="mt-0.5 h-4 w-4 shrink-0 text-gold" aria-hidden="true" />
<p><strong className="font-semibold text-ink">Dica de engenharia:</strong> {erro.dicaPro}</p>
</div>
</div>
)}
</article>
);
})
)}
</div>
</section>
<section className="shell pb-20 md:pb-28" aria-labelledby="checklist-titulo">
<h2 id="checklist-titulo" className="section-title">Checklist antes de ir para campo</h2>
<p className="mt-3 max-w-2xl text-base text-muted">Itens essenciais para validar no hardware e no firmware antes de entregar o produto.</p>
<div className="mt-8 grid gap-4 md:grid-cols-2">
{CHECKLISTS.map(({ icon: Icon, titulo, itens }) => (
<div key={titulo} className="card p-5 sm:p-7">
<h3 className="flex items-center gap-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
<span className="grid h-9 w-9 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-4 w-4" aria-hidden="true" />
</span>
{titulo}
</h3>
<ul className="mt-5 space-y-3">
{itens.map((item) => (
<li key={item} className="flex items-start gap-3 text-sm leading-relaxed text-ink-soft">
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
{item}
</li>
))}
</ul>
</div>
))}
</div>
</section>
</main>
<Footer />
</div>
);
}
-180
View File
@@ -1,180 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import { notFound } from "next/navigation";
import CodeExample from "@/components/CodeExample";
import frameworksData from "@/public/frameworks.json";
import { ArrowRight, ArrowUpRight, BookOpen, Box, Check, Code, Layers } from "lucide-react";
export default async function FrameworkDetail({ params }) {
const { key } = await params;
const framework = frameworksData[key];
if (!framework) {
notFound();
}
const features = framework.caracteristicas || [];
const useCases = framework.casos_uso || [];
const isEspIdf = key === "ESP-IDF";
return (
<div className="site-canvas min-h-screen">
{/* Ficha técnica do framework e trilha de navegação para o Google */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.framework(key, framework)) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Frameworks", caminho: "/frameworks" },
{ nome: framework.nome, caminho: `/frameworks/${encodeURIComponent(key)}` },
])),
}}
/>
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Frameworks e SDKs", href: "/frameworks" }, { label: framework.nome }]}
icon={Layers}
label={framework.tipo}
title={framework.nome}
lede={framework.descricao}
>
{framework.documentacao && (
<a href={framework.documentacao} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
<BookOpen className="h-4 w-4" aria-hidden="true" />
Documentação oficial
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
{framework.repositorio && (
<a href={framework.repositorio} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
<Code className="h-4 w-4" aria-hidden="true" />
Repositório no GitHub
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
</PageHero>
<section className="shell mt-10" aria-label="Resumo">
<dl className="grid gap-3 md:grid-cols-3">
<div className="tile">
<dt className="text-xs font-medium text-muted">Linguagem</dt>
<dd className="mt-1 font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{framework.linguagem}</dd>
<dd className="mt-0.5 text-xs text-muted">{framework.nome_completo}</dd>
</div>
<div className="tile">
<dt className="text-xs font-medium text-muted">Categoria</dt>
<dd className="mt-1 font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{framework.tipo}</dd>
</div>
<div className="tile">
<dt className="text-xs font-medium text-muted">Objetivo principal</dt>
<dd className="mt-1 text-sm font-medium leading-relaxed text-ink">{framework.funcao_principal}</dd>
</div>
</dl>
</section>
<section className="shell mt-12 grid gap-5 lg:grid-cols-2" aria-label="Recursos e aplicações">
<div className="card p-5 sm:p-7">
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">Recursos de destaque</h2>
<ul className="mt-5 space-y-3">
{features.map((feature) => (
<li key={feature} className="flex items-start gap-3 text-sm leading-relaxed text-ink-soft">
<Check className="mt-0.5 h-4 w-4 shrink-0 text-ok" aria-hidden="true" />
{feature}
</li>
))}
</ul>
</div>
<div className="card p-5 sm:p-7">
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">Quando usar</h2>
<ul className="mt-5 space-y-2.5">
{useCases.map((useCase) => (
<li key={useCase} className="tile text-sm font-medium text-ink-soft">
{useCase}
</li>
))}
</ul>
</div>
</section>
{isEspIdf && (
<section className="shell mt-8">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<span className="chip chip-accent">
<Box className="h-3.5 w-3.5" aria-hidden="true" />
ESP-IDF 4.4 ou superior
</span>
<h2 className="section-title mt-4">Módulos com o ESP Component Registry</h2>
<p className="mt-3 text-base leading-relaxed text-muted">
Nos projetos ESP-IDF v4.4+ e v5.x, as bibliotecas não precisam mais entrar como submódulos Git. Use o{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code> e o comando{" "}
<code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf.py add-dependency</code> para baixar drivers de display (LVGL), pilhas industriais (Modbus), RainMaker e mais.
</p>
</div>
<Link href="/componentes" className="btn btn-primary shrink-0">
Explorar componentes
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
)}
{framework.exemplo && (
<section className="shell mt-8">
<CodeExample framework={framework} />
</section>
)}
<div className="shell section pt-10">
<Link href="/frameworks" className="inline-flex min-h-11 items-center gap-2 text-sm font-medium text-accent hover:text-accent-strong">
<ArrowRight className="h-4 w-4 rotate-180" aria-hidden="true" />
Ver todos os frameworks
</Link>
</div>
</main>
<Footer />
</div>
);
}
export async function generateMetadata({ params }) {
const { key } = await params;
const framework = frameworksData[key];
if (!framework) {
return { title: "Framework não encontrado", robots: { index: false, follow: false } };
}
return {
...paginaMeta({
titulo: `${framework.nome} para ESP32 · Guia Técnico`,
descricao: `${framework.nome_completo}: ${framework.descricao} Guia com exemplos práticos de código e casos de uso.`,
caminho: `/frameworks/${encodeURIComponent(key)}`,
tipo: "article",
keywords: [
framework.nome, framework.nome_completo,
`${framework.nome} ESP32`, `programar ESP32 com ${framework.nome}`,
"ESP32", "framework ESP32",
],
}),
other: { "article:section": "Frameworks" },
};
}
export async function generateStaticParams() {
return Object.keys(frameworksData).map((key) => ({
key: key,
}));
}
-39
View File
@@ -1,39 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Frameworks & SDKs para ESP32: Guia Completo e Comparativo",
descricao: "Guia completo de desenvolvimento: ESP-IDF, ESP-RainMaker, ESP-Matter, Rust, ESP-ADF, ESP-SR, ESP-WHO, Arduino e MicroPython com exemplos de código.",
caminho: "/frameworks",
keywords: [
"ESP-IDF",
"ESP-RainMaker",
"ESP-Matter",
"Rust ESP32",
"ESP-SR",
"ESP-ADF",
"ESP-IoT-Solution",
"Arduino ESP32",
"MicroPython ESP32",
"frameworks ESP32",
"programar ESP32",
],
});
export default function FrameworksLayout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Frameworks", caminho: "/frameworks" },
])
),
}}
/>
{children}
</>
);
}
-136
View File
@@ -1,136 +0,0 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import SectionHead from "@/components/SectionHead";
import Link from "next/link";
import frameworksData from "@/public/frameworks.json";
import { ArrowRight, ArrowUpRight, Box, Brain, Cloud, GraduationCap, Layers, Mic, Music, Sparkles } from "lucide-react";
const GUIAS = [
{
icon: GraduationCap,
titulo: "Estou começando",
texto: "Arduino ou MicroPython são os caminhos mais rápidos para testar sensores e APIs. Para produto, vá de ESP-IDF ou Rust.",
links: [
["Arduino", "/frameworks/Arduino"],
["MicroPython", "/frameworks/MicroPython"],
["Rust", "/frameworks/Rust-ESP"],
],
},
{
icon: Cloud,
titulo: "Nuvem e casa conectada",
texto: "ESP-Matter para interoperabilidade, ESP-RainMaker para nuvem pronta e Zigbee para redes locais de baixo consumo.",
links: [
["RainMaker", "/frameworks/ESP-RainMaker"],
["Matter", "/frameworks/ESP-Matter"],
["Zigbee", "/frameworks/ESP-Zigbee-SDK"],
],
},
{
icon: Sparkles,
titulo: "Áudio, voz e IA",
texto: "ESP-ADF para áudio, ESP-SR para reconhecimento de fala offline e ESP-NN para acelerar TinyML.",
links: [
["Áudio", "/frameworks/ESP-ADF", Music],
["Voz", "/frameworks/ESP-SR", Mic],
["IA", "/frameworks/ESP-NN", Brain],
],
},
];
export default function Frameworks() {
const frameworks = Object.entries(frameworksData);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Frameworks e SDKs" }]}
icon={Layers}
label={`${frameworks.length} frameworks e SDKs`}
title="Frameworks e SDKs do ESP32"
lede="Do C/C++ nativo com FreeRTOS ao Rust, passando por nuvem IoT, reconhecimento de voz, áudio e Matter. Escolha pelo que você quer construir."
/>
<section className="shell pt-10 sm:pt-12" aria-label="Por onde começar">
<div className="grid gap-4 md:grid-cols-3">
{GUIAS.map(({ icon: Icon, titulo, texto, links }) => (
<div key={titulo} className="card flex flex-col p-5 sm:p-6">
<span className="grid h-10 w-10 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<h2 className="mt-4 font-display text-xl font-semibold tracking-[-0.03em] text-ink">{titulo}</h2>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{texto}</p>
<ul className="mt-5 flex flex-wrap gap-2 border-t border-line pt-4">
{links.map(([rotulo, href, Extra]) => (
<li key={rotulo}>
<Link href={href} className="chip-btn">
{Extra && <Extra className="h-4 w-4" aria-hidden="true" />}
{rotulo}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
</section>
<section className="shell mt-10">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<span className="chip chip-accent">
<Box className="h-3.5 w-3.5" aria-hidden="true" />
Arquitetura modular
</span>
<h2 className="section-title mt-4">ESP Component Registry</h2>
<p className="mt-3 text-base leading-relaxed text-muted">
Instale drivers de display (LVGL), pilhas industriais (Modbus), recursos de nuvem e pacotes de placa
(BSPs) com uma linha no manifesto <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-sm">idf_component.yml</code>.
</p>
</div>
<Link href="/componentes" className="btn btn-primary shrink-0">
Explorar componentes
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
<section className="shell section" aria-labelledby="todos-titulo">
<SectionHead id="todos-titulo" eyebrow="Todos" title="Todos os frameworks" lede="Cada ficha traz recursos, aplicações ideais, exemplo de código e links oficiais." />
<div className="mt-8 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{frameworks.map(([key, framework]) => (
<Link key={key} href={`/frameworks/${encodeURIComponent(key)}`} className="card card-interactive group flex flex-col p-5 sm:p-6">
<div className="flex flex-wrap items-start justify-between gap-2">
<h3 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">{framework.nome}</h3>
<span className="chip max-w-full">{framework.linguagem}</span>
</div>
<p className="mt-1 text-sm text-muted">{framework.tipo}</p>
<p className="mt-3 line-clamp-3 text-sm leading-relaxed text-muted">{framework.descricao}</p>
<ul className="mt-5 flex flex-1 flex-wrap content-start gap-1.5">
{framework.casos_uso.slice(0, 3).map((caso) => (
<li key={caso} className="chip max-w-full">
<span className="truncate">{caso}</span>
</li>
))}
</ul>
<span className="mt-5 inline-flex items-center gap-1 border-t border-line pt-4 text-sm font-medium text-accent">
Ver detalhes e exemplo
<ArrowUpRight className="h-4 w-4 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
))}
</div>
</section>
</main>
<Footer />
</div>
);
}
+24
View File
@@ -759,4 +759,28 @@
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* ------------------------------------------------------------------------
Tipografia e layout internacionalizados (seção 9b da spec)
------------------------------------------------------------------------ */
html[lang="zh-CN"] {
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Noto Sans SC", sans-serif;
letter-spacing: 0;
line-height: 1.7;
}
html[lang="zh-CN"] code,
html[lang="zh-CN"] pre,
html[lang="zh-CN"] kbd {
font-family: var(--font-mono);
}
html[lang="de"],
html[lang="fr"] {
hyphens: auto;
}
p, li, dd {
overflow-wrap: anywhere;
}
}
-54
View File
@@ -1,54 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import { categoriasGlossario } from "@/lib/glossarioData";
export const metadata = paginaMeta({
titulo: "Glossário Técnico do ESP32: Termos e Conceitos",
descricao: "Mais de 50 termos e conceitos essenciais do ecossistema ESP32 explicados em português: GPIO, Strapping Pins, ULP, PSRAM, FreeRTOS, eFuse, Deep Sleep, OTA, Secure Boot, ECDSA, Matter e Thread.",
caminho: "/glossario",
keywords: [
"glossário ESP32",
"o que é GPIO",
"o que é strapping pins",
"o que é ULP ESP32",
"o que é PSRAM ESP32",
"termos técnicos microcontrolador",
"conceitos ESP32 português",
],
});
export default function GlossarioLayout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.glossario(categoriasGlossario)),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Glossário Técnico", caminho: "/glossario" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Glossário Técnico do ESP32",
descricao: "Enciclopédia de termos técnicos e conceitos de hardware e software do ecossistema ESP32.",
caminho: "/glossario",
})
),
}}
/>
{children}
</>
);
}
-334
View File
@@ -1,334 +0,0 @@
"use client";
import { useState, useMemo, useRef } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Link from "next/link";
import { categoriasGlossario } from "@/lib/glossarioData";
import {
ArrowRight,
BookOpen,
Check,
Code2,
Cpu,
Database,
HelpCircle,
LayoutGrid,
Lightbulb,
Link2,
BatteryCharging,
RotateCcw,
Search,
ShieldCheck,
Sliders,
Sparkles,
Wifi,
X,
} from "lucide-react";
const BUSCAS_POPULARES = ["GPIO", "ULP", "PSRAM", "Strapping Pins", "Deep Sleep", "OTA", "Matter", "Secure Boot", "Wi-Fi 6", "MIPI"];
const ICONES = { Cpu, Database, Wifi, Sliders, Sparkles, BatteryCharging, Code2, ShieldCheck };
/** "Processamento, CPU & Silício" vira "Processamento": cabe no filtro sem truncar. */
const nomeCurto = (nome) => nome.split(/,| &/)[0].trim();
export default function GlossarioPage() {
const [busca, setBusca] = useState("");
const [categoriaSelecionada, setCategoriaSelecionada] = useState("todas");
const [letraFiltro, setLetraFiltro] = useState(null);
const [copiadoSlug, setCopiadoSlug] = useState(null);
const searchInputRef = useRef(null);
const todosOsTermos = useMemo(
() =>
categoriasGlossario.flatMap((cat) =>
cat.termos.map((t) => ({
...t,
categoriaId: cat.id,
categoriaNome: cat.nome,
categoriaIcone: cat.icone,
slug: t.termo.toLowerCase().replace(/[\s()/²]+/g, "-"),
primeiraLetra: t.termo.charAt(0).toUpperCase(),
}))
),
[]
);
const alfabeto = useMemo(() => {
const disponiveis = new Set(todosOsTermos.map((t) => t.primeiraLetra));
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((letra) => ({ letra, temTermos: disponiveis.has(letra) }));
}, [todosOsTermos]);
const termosFiltrados = useMemo(() => {
const termoBusca = busca.toLowerCase().trim();
return todosOsTermos.filter((item) => {
const matchCategoria = categoriaSelecionada === "todas" || item.categoriaId === categoriaSelecionada;
const matchLetra = !letraFiltro || item.primeiraLetra === letraFiltro;
const matchBusca =
!termoBusca ||
item.termo.toLowerCase().includes(termoBusca) ||
item.definicao.toLowerCase().includes(termoBusca) ||
item.exemplo.toLowerCase().includes(termoBusca) ||
item.categoriaNome.toLowerCase().includes(termoBusca);
return matchCategoria && matchLetra && matchBusca;
});
}, [todosOsTermos, categoriaSelecionada, letraFiltro, busca]);
const temFiltroAtivo = busca.trim() !== "" || categoriaSelecionada !== "todas" || letraFiltro !== null;
const limparTodosFiltros = () => {
setBusca("");
setCategoriaSelecionada("todas");
setLetraFiltro(null);
searchInputRef.current?.focus();
};
const copiarLinkTermo = (slug) => {
navigator.clipboard.writeText(`${window.location.origin}/glossario#${slug}`);
setCopiadoSlug(slug);
setTimeout(() => setCopiadoSlug(null), 2000);
};
const total = termosFiltrados.length;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Glossário" }]}
icon={BookOpen}
label={`${todosOsTermos.length} termos explicados`}
title="Glossário técnico do ESP32"
lede="Definições diretas, parâmetros de hardware e um exemplo prático para cada termo do ecossistema, de ADC a Secure Boot."
/>
<section className="shell pt-10 sm:pt-12" aria-label="Busca e filtros">
<div className="panel p-5 sm:p-7">
<div className="relative">
<label htmlFor="busca-glossario" className="sr-only">
Buscar termo, sigla ou conceito
</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-glossario"
ref={searchInputRef}
type="search"
value={busca}
onChange={(e) => setBusca(e.target.value)}
placeholder="Buscar termo, sigla ou conceito"
autoComplete="off"
className={`field pl-12 text-base ${busca ? "pr-28" : "pr-4"}`}
/>
<div className="absolute right-2 top-1/2 -translate-y-1/2">
{busca && (
<button type="button" onClick={() => { setBusca(""); searchInputRef.current?.focus(); }} className="btn btn-ghost btn-sm">
<X className="h-3.5 w-3.5" aria-hidden="true" />
Limpar
</button>
)}
</div>
</div>
<div className="mt-4 flex flex-wrap items-center gap-2">
<span className="mr-1 text-sm text-muted">Mais buscados</span>
{BUSCAS_POPULARES.map((rotulo) => (
<button
key={rotulo}
type="button"
onClick={() => setBusca(rotulo)}
aria-pressed={busca.toLowerCase() === rotulo.toLowerCase()}
className="chip-btn"
>
{rotulo}
</button>
))}
</div>
<div className="mt-7 border-t border-line pt-6">
<h2 className="text-sm font-semibold text-ink">Categoria</h2>
<div className="mt-3 flex flex-wrap gap-2">
<button type="button" onClick={() => setCategoriaSelecionada("todas")} aria-pressed={categoriaSelecionada === "todas"} className="chip-btn">
<LayoutGrid className="h-4 w-4" aria-hidden="true" />
Todas
<span className="tabular-nums opacity-80">{todosOsTermos.length}</span>
</button>
{categoriasGlossario.map((cat) => {
const Icone = ICONES[cat.icone] ?? Cpu;
return (
<button
key={cat.id}
type="button"
onClick={() => setCategoriaSelecionada(cat.id)}
aria-pressed={categoriaSelecionada === cat.id}
className="chip-btn"
>
<Icone className="h-4 w-4" aria-hidden="true" />
{nomeCurto(cat.nome)}
<span className="tabular-nums opacity-80">{cat.termos.length}</span>
</button>
);
})}
</div>
</div>
<div className="mt-6 border-t border-line pt-6">
<h2 className="text-sm font-semibold text-ink">Ordem alfabética</h2>
<div className="mt-3 flex flex-wrap gap-1.5" role="group" aria-label="Filtrar pela letra inicial">
<button type="button" onClick={() => setLetraFiltro(null)} aria-pressed={letraFiltro === null} className="chip-btn">
Todas
</button>
{alfabeto.map(({ letra, temTermos }) => (
<button
key={letra}
type="button"
disabled={!temTermos}
onClick={() => setLetraFiltro(letraFiltro === letra ? null : letra)}
aria-pressed={letraFiltro === letra}
className="chip-btn min-w-11 justify-center px-0 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-surface"
>
{letra}
</button>
))}
</div>
</div>
</div>
</section>
<section className="shell section pt-8 sm:pt-10" aria-labelledby="resultado-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="resultado-titulo" className="text-base font-semibold text-ink" role="status" aria-live="polite">
{total} {total === 1 ? "termo" : "termos"}
{temFiltroAtivo && <span className="font-normal text-muted"> com os filtros atuais</span>}
</h2>
{temFiltroAtivo && (
<button type="button" onClick={limparTodosFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
Redefinir filtros
</button>
)}
</div>
{total === 0 ? (
<div className="card mt-6 px-6 py-14 text-center">
<HelpCircle className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<h3 className="mt-4 font-display text-xl font-semibold text-ink">Nenhum termo encontrado</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
Nada combina com a busca e os filtros atuais. Tente uma sigla mais curta ou volte para todas as categorias.
</p>
<button type="button" onClick={limparTodosFiltros} className="btn btn-primary mt-6">
<RotateCcw className="h-4 w-4" aria-hidden="true" />
Limpar filtros
</button>
</div>
) : (
<div className="mt-6 grid gap-4 md:grid-cols-2">
{termosFiltrados.map((item) => {
const Icone = ICONES[item.categoriaIcone] ?? Cpu;
return (
<article key={item.slug} id={item.slug} className="card flex scroll-mt-28 flex-col p-5 sm:p-6">
<div className="flex items-center justify-between gap-3">
<span className="chip">
<Icone className="h-3.5 w-3.5 text-accent" aria-hidden="true" />
{nomeCurto(item.categoriaNome)}
</span>
<button
type="button"
onClick={() => copiarLinkTermo(item.slug)}
aria-label={`Copiar link para ${item.termo}`}
className="btn-icon inline-flex h-11 w-11 items-center justify-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-accent"
>
{copiadoSlug === item.slug ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Link2 className="h-4 w-4" aria-hidden="true" />}
</button>
</div>
<h3 className="mt-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">{item.termo}</h3>
<p className="mt-2 text-[0.9375rem] leading-relaxed text-muted">
<TextoComLinks texto={item.definicao} />
</p>
<div className="callout mt-5">
<p className="flex items-center gap-1.5 text-sm font-semibold text-ink">
<Lightbulb className="h-4 w-4 text-accent" aria-hidden="true" />
Na prática
</p>
<p className="mt-1">
<TextoComLinks texto={item.exemplo} />
</p>
</div>
</article>
);
})}
</div>
)}
</section>
<section className="shell pb-20 md:pb-28">
<div className="panel p-8 text-center sm:p-12">
<h2 className="section-title mx-auto max-w-2xl">Do conceito ao chip certo.</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
Com os termos em mãos, compare as séries lado a lado ou responda ao seletor para chegar ao modelo que cabe no seu projeto.
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href="/seletor" className="btn btn-primary w-full sm:w-auto">
<Sliders className="h-4 w-4" aria-hidden="true" />
Escolher meu chip
</Link>
<Link href="/series" className="btn btn-ghost w-full sm:w-auto">
Explorar as séries
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
/**
* Função utilitária que detecta nomes de séries do ESP32 dentro do texto e os converte em links clicáveis.
*/
function TextoComLinks({ texto }) {
if (!texto) return null;
const seriesKeys = [
"ESP32-S31",
"ESP32-C61",
"ESP32-S2",
"ESP32-S3",
"ESP32-C2",
"ESP32-C3",
"ESP32-C5",
"ESP32-C6",
"ESP32-P4",
"ESP32-H2",
"ESP32-H4",
"ESP32",
];
const regex = new RegExp(`\\b(${seriesKeys.join("|")})\\b`, "g");
const partes = texto.split(regex);
return (
<>
{partes.map((parte, i) => {
if (seriesKeys.includes(parte)) {
return (
<Link
key={i}
href={`/series/${parte}`}
className="font-semibold text-accent underline decoration-accent/30 underline-offset-2 hover:decoration-accent"
>
{parte}
</Link>
);
}
return parte;
})}
</>
);
}
-134
View File
@@ -1,134 +0,0 @@
import { JetBrains_Mono, Manrope, Space_Grotesk } from "next/font/google";
import "./globals.css";
import Providers from "@/components/Providers";
import { SITE, jsonLd } from "@/lib/seo";
const spaceGrotesk = Space_Grotesk({
subsets: ["latin"],
variable: "--font-space-grotesk",
display: "swap",
weight: ["500", "600", "700"],
});
const manrope = Manrope({
subsets: ["latin"],
variable: "--font-manrope",
display: "swap",
weight: ["400", "500", "600", "700"],
});
const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains",
display: "swap",
weight: ["400", "500", "600"],
});
export const metadata = {
// metadataBase é o que transforma caminhos relativos em URLs absolutas nas
// tags canonical e og:image. Sem ele, o Google recebe og:image quebrado.
metadataBase: new URL(SITE.url),
title: {
default: "ESPDocs · Documentação do ESP32 em português",
// Cada página fornece só o próprio nome; o sufixo entra automaticamente.
template: "%s · ESPDocs",
},
description:
"Especificações, pinagem, comparação e seleção das 12 séries de microcontroladores ESP32, em português brasileiro. Datasheets, periféricos, segurança em hardware e diagramas de conexão.",
applicationName: "ESPDocs",
authors: [{ name: "Lucas Rayan Guerra", url: "https://lucasrguerra.dev.br" }],
creator: "Lucas Rayan Guerra",
publisher: "Ciência Embarcada",
category: "technology",
keywords: [
"ESP32", "ESP32 português", "documentação ESP32", "pinout ESP32",
"ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4", "ESP32-H2",
"comparar ESP32", "qual ESP32 escolher", "datasheet ESP32",
"microcontrolador", "Espressif", "ESP-IDF", "IoT", "sistemas embarcados",
],
alternates: { canonical: "/" },
openGraph: {
type: "website",
locale: "pt_BR",
url: SITE.url,
siteName: "ESPDocs",
title: "ESPDocs · Documentação do ESP32 em português",
description:
"Especificações, pinagem, comparação e seleção das 12 séries de microcontroladores ESP32, em português brasileiro.",
},
twitter: {
card: "summary_large_image",
title: "ESPDocs · Documentação do ESP32 em português",
description:
"Especificações, pinagem, comparação e seleção das 12 séries de ESP32, em português.",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-image-preview": "large",
"max-snippet": -1,
"max-video-preview": -1,
},
},
icons: {
icon: [
{ url: "/favicon.ico", sizes: "48x48", type: "image/x-icon" },
{ url: "/favicon-48x48.png", sizes: "48x48", type: "image/png" },
{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" },
{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" },
{ url: "/icon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/icon-512.png", sizes: "512x512", type: "image/png" },
{ url: "/icon.svg", type: "image/svg+xml" },
],
apple: [
{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" },
],
shortcut: "/favicon.ico",
},
manifest: "/site.webmanifest",
formatDetection: { telephone: false, address: false, email: false },
};
export const viewport = {
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#f5f6f8" },
{ media: "(prefers-color-scheme: dark)", color: "#07090d" },
],
};
export default function RootLayout({ children }) {
return (
<html lang="pt-BR" className={`${spaceGrotesk.variable} ${manrope.variable} ${jetbrainsMono.variable}`} suppressHydrationWarning>
<head>
{/* Dados estruturados do site e da organização. É o que permite ao
Google montar o box de busca interna e entender a autoria. */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.siteESociedade()) }}
/>
</head>
<body className="font-sans antialiased bg-canvas text-ink overflow-x-clip" suppressHydrationWarning>
<a
href="#conteudo"
className="sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-[200] focus:rounded-full focus:bg-ink focus:px-5 focus:py-3 focus:text-sm focus:font-semibold focus:text-canvas"
>
Pular para o conteúdo
</a>
<Providers>
{children}
</Providers>
</body>
</html>
);
}
-58
View File
@@ -1,58 +0,0 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import Link from "next/link";
import { ArrowRight, BookOpen, Compass, Scale, SlidersHorizontal } from "lucide-react";
export const metadata = {
title: "Página não encontrada",
robots: { index: false, follow: false },
};
const CAMINHOS = [
{ href: "/series", icon: Compass, titulo: "Séries ESP32", texto: "As 12 famílias, com pinagem e especificações." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Seletor de chip", texto: "Responda a oito perguntas e receba os modelos indicados." },
{ href: "/comparacao", icon: Scale, titulo: "Comparador", texto: "Até quatro séries lado a lado." },
{ href: "/glossario", icon: BookOpen, titulo: "Glossário", texto: "Termos de hardware explicados em português." },
];
export default function NotFound() {
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo" className="shell section">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow justify-center">Erro 404</p>
<h1 className="page-title mt-4">Essa página não existe.</h1>
<p className="lede mx-auto mt-5 max-w-xl">
O endereço pode ter mudado ou estar digitado errado. Escolha um destes caminhos para continuar.
</p>
<div className="mt-8 flex justify-center">
<Link href="/" className="btn btn-primary">
Voltar ao início
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
<ul className="mx-auto mt-14 grid max-w-4xl gap-3 sm:grid-cols-2">
{CAMINHOS.map(({ href, icon: Icon, titulo, texto }) => (
<li key={href}>
<Link href={href} className="card card-interactive group flex h-full items-start gap-4 p-5">
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<span>
<span className="block font-semibold text-ink">{titulo}</span>
<span className="mt-0.5 block text-sm text-muted">{texto}</span>
</span>
</Link>
</li>
))}
</ul>
</main>
<Footer />
</div>
);
}
-341
View File
@@ -1,341 +0,0 @@
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import BookCover from "@/components/BookCover";
import Link from "next/link";
import seriesData from "@/public/series.json";
import frameworksData from "@/public/frameworks.json";
import { SITE } from "@/lib/seo";
import {
AlertTriangle,
ArrowRight,
ArrowUpRight,
BookOpen,
Box,
Cpu,
Scale,
SlidersHorizontal,
Terminal,
} from "lucide-react";
const FEATURED = ["ESP32", "ESP32-S3", "ESP32-C6", "ESP32-C3", "ESP32-P4", "ESP32-H2"];
const TOOLS = [
{
href: "/seletor",
title: "Seletor inteligente",
desc: "Responda oito perguntas sobre o projeto e receba os chips mais compatíveis, com justificativa técnica.",
icon: SlidersHorizontal,
action: "Encontrar meu chip",
},
{
href: "/comparacao",
title: "Comparador de séries",
desc: "Coloque até quatro modelos lado a lado e compare núcleos, rádio, memória, periféricos e segurança.",
icon: Scale,
action: "Comparar agora",
},
{
href: "/diagnostico",
title: "Diagnóstico de falhas",
desc: "Causas e correções para brownout, bootloop, Guru Meditation, watchdog e falhas de flash.",
icon: AlertTriangle,
action: "Abrir diagnóstico",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, bibliotecas e BSPs do registro oficial da Espressif, com manifesto pronto para o projeto.",
icon: Box,
action: "Explorar componentes",
},
{
href: "/frameworks",
title: "Frameworks e SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython e as ferramentas que ficam em volta do chip.",
icon: Terminal,
action: "Ver frameworks",
},
{
href: "/catalogo",
title: "Catálogo de placas",
desc: "DevKits e módulos reais, com interface USB, sensores integrados e link para a loja oficial.",
icon: Cpu,
action: "Ver placas",
},
];
const ERRORS = [
{
code: "Brownout detector was triggered",
cause: "Queda de tensão na inicialização do rádio.",
fix: "Capacitor de 10–100 µF junto ao chip e fonte de 5 V com corrente suficiente.",
},
{
code: "Guru Meditation Error",
cause: "Ponteiro inválido, stack overflow ou uso incorreto de interrupção.",
fix: "Leia o backtrace com addr2line e dimensione a stack da task no FreeRTOS.",
},
{
code: "ADC2 indisponível com Wi-Fi",
cause: "O controlador de rádio reserva o ADC2 enquanto está ativo.",
fix: "Use os pinos do ADC1 para sensores analógicos que convivem com o Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tensão ou modo de flash incorretos, ou pino de strapping preso no boot.",
fix: "Confira 3,3 V, pull-ups de boot e a configuração de flash no esptool.",
},
];
export default function Home() {
const seriesCount = Object.keys(seriesData).length;
const frameworkCount = Object.keys(frameworksData).length;
const featured = FEATURED.map((key) => [key, seriesData[key]]).filter(([, serie]) => Boolean(serie));
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<section className="shell pb-10 pt-14 sm:pt-20 lg:pb-14 lg:pt-24">
<div className="mx-auto max-w-4xl text-center">
<span className="chip chip-accent">
<Cpu className="h-3.5 w-3.5" aria-hidden="true" />
Documentação aberta do ESP32
</span>
<h1 className="display mt-6 text-[clamp(2.9rem,7.4vw,5.4rem)]">
O ESP32,
<br className="sm:hidden" /> sem ruído.
</h1>
<p className="lede mx-auto mt-6 max-w-2xl">
Especificações, pinagem, comparações e diagnóstico em uma leitura só.
Menos tradução de datasheet, mais tempo com o protótipo na bancada.
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href="/seletor" className="btn btn-primary w-full sm:w-auto">
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
Escolher meu chip
</Link>
<Link href="/series" className="btn btn-ghost w-full sm:w-auto">
Explorar as {seriesCount} séries
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<p className="mt-7 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-sm text-muted">
<span><strong className="font-semibold text-ink">{seriesCount}</strong> séries</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">{frameworkCount}</strong> frameworks</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">78</strong> capítulos no livro</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% em português</span>
</p>
</div>
<div className="panel mt-12 overflow-hidden sm:mt-16">
<div className="flex flex-wrap items-center justify-between gap-3 px-5 py-4 sm:px-7">
<div>
<h2 className="text-sm font-semibold text-ink">Séries em destaque</h2>
<p className="mt-0.5 text-xs text-muted">O essencial de cada família, antes de abrir o datasheet.</p>
</div>
<Link href="/series" className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent transition-colors hover:text-accent-strong">
Índice completo
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<div className="grid gap-px border-t border-line bg-line sm:grid-cols-2 lg:grid-cols-3">
{featured.map(([key, serie]) => (
<Link
key={key}
href={`/series/${key}`}
className="group flex min-w-0 flex-col bg-surface p-5 transition-colors duration-300 hover:bg-surface-2 sm:p-6"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h3 className="font-display text-xl font-semibold tracking-[-0.035em] text-ink">{key}</h3>
<p className="mt-1 truncate text-xs text-muted">{serie.arquitetura}</p>
</div>
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-full bg-accent-soft text-accent transition-transform duration-300 group-hover:scale-105">
<Cpu className="h-4 w-4" aria-hidden="true" />
</span>
</div>
<p className="mt-5 line-clamp-2 text-sm leading-relaxed text-muted">{serie.descricao}</p>
<div className="mt-5 flex items-center justify-between gap-3 border-t border-line pt-3.5">
<span className="truncate font-mono text-[0.6875rem] text-ink-soft">{serie.frequencia}</span>
<span className="inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent">
Ficha
<ArrowUpRight className="h-3.5 w-3.5 transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</div>
</Link>
))}
</div>
</div>
</section>
<section className="shell section pt-8 sm:pt-12" aria-labelledby="livro-titulo">
<div className="relative isolate overflow-hidden rounded-[2rem] bg-[#0b0d10] ring-1 ring-white/10 dark:bg-[#05070a] dark:ring-white/15 sm:rounded-[2.5rem]">
<div
className="pointer-events-none absolute -left-24 top-1/2 -z-10 h-80 w-80 -translate-y-1/2 rounded-full bg-[#2dd4bf]/15 blur-3xl"
aria-hidden="true"
/>
<div className="grid lg:grid-cols-[0.82fr_1.18fr]">
<div className="order-1 flex flex-col justify-center p-7 sm:p-10 lg:order-2 lg:p-14">
<span className="inline-flex w-fit items-center gap-2 rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold text-[#75cdc1]">
<BookOpen className="h-3.5 w-3.5" aria-hidden="true" />
Livro novo
</span>
<h2 id="livro-titulo" className="mt-5 font-display text-[clamp(2rem,4.2vw,3.2rem)] font-semibold leading-[1.05] tracking-[-0.04em] text-[#f4f6f8]">
{SITE.livroTitulo}
</h2>
<p className="mt-2 text-base text-[#a6afbd]">{SITE.livroSubtitulo}</p>
<p className="mt-5 max-w-xl text-sm leading-relaxed text-[#c4cbd5]">
Um percurso completo pelo hardware e pelo firmware do ESP32: da arquitetura do chip
à implantação de produtos conectados. São 12 partes e 78 capítulos sobre Arduino,
ESP-IDF, FreeRTOS, Wi-Fi, BLE, Thread e Matter, periféricos, depuração, baixo consumo
e segurança.
</p>
<p className="mt-6 flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-[#a6afbd]">
<span>12 partes</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>78 capítulos</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>ISBN {SITE.livroIsbn}</span>
</p>
<div className="mt-7 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
<a
href={SITE.livroAmazon}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full bg-[#2dd4bf] px-5 text-sm font-semibold text-[#06201d] transition-colors duration-300 hover:bg-[#5eead4]"
>
Comprar digital
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<a
href={SITE.livroUiclap}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full border border-white/20 px-5 text-sm font-semibold text-[#f4f6f8] transition-colors duration-300 hover:border-white/40 hover:bg-white/5"
>
Comprar impresso
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<Link href="/livro" className="inline-flex min-h-11 items-center justify-center gap-1.5 rounded-full px-3 text-sm font-medium text-[#a6afbd] transition-colors duration-300 hover:text-[#f4f6f8]">
Ficha completa
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
<div className="order-2 flex items-center justify-center border-t border-white/10 p-8 sm:p-12 lg:order-1 lg:border-r lg:border-t-0 lg:p-14">
<div className="relative w-[min(15.5rem,68%)] lg:w-[min(17rem,100%)]">
<div className="absolute -inset-10 -z-10 rounded-full bg-[#2dd4bf]/10 blur-3xl" aria-hidden="true" />
<BookCover />
</div>
</div>
</div>
</div>
</section>
<section className="shell section" aria-labelledby="ferramentas-titulo">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow">Ferramentas</p>
<h2 id="ferramentas-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
Comece pelo problema.
</h2>
<p className="lede mt-4">
Cada ferramenta resolve uma etapa concreta do projeto, sem cadastro e sem rodeio.
</p>
</div>
<div className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{TOOLS.map((tool) => {
const Icon = tool.icon;
return (
<Link key={tool.href} href={tool.href} className="card card-interactive group flex flex-col p-5 sm:p-6">
<span className="grid h-11 w-11 place-items-center rounded-2xl bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<h3 className="mt-5 font-display text-lg font-semibold tracking-[-0.025em] text-ink">{tool.title}</h3>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{tool.desc}</p>
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-accent">
{tool.action}
<ArrowRight className="h-4 w-4 transition-transform duration-300 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
);
})}
</div>
</section>
<section className="shell section pt-0" aria-labelledby="diagnostico-titulo">
<div className="grid items-start gap-10 lg:grid-cols-[0.78fr_1.22fr] lg:gap-16">
<div className="lg:sticky lg:top-28">
<p className="eyebrow">Diagnóstico</p>
<h2 id="diagnostico-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
O primeiro boot não precisa virar noite.
</h2>
<p className="lede mt-4">
Os erros mais comuns têm causa conhecida. O guia parte da mensagem no terminal e chega ao ajuste de hardware ou firmware.
</p>
<Link href="/diagnostico" className="btn btn-accent mt-7">
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
Abrir os 30+ diagnósticos
</Link>
</div>
<div className="panel-dark min-w-0 overflow-hidden rounded-[1.75rem]">
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-white/10 px-5 py-4 sm:px-6">
<span className="inline-flex items-center gap-2 font-mono text-xs text-[#75cdc1]">
<Terminal className="h-4 w-4" aria-hidden="true" />
boot.log
</span>
<span className="text-xs text-[#a6afbd]">4 exemplos de 30+</span>
</div>
<div className="divide-y divide-white/10">
{ERRORS.map((item) => (
<Link key={item.code} href="/diagnostico" className="group grid gap-2 px-5 py-5 transition-colors duration-300 hover:bg-white/[0.035] sm:px-6">
<span className="break-words font-mono text-[0.75rem] font-medium leading-relaxed text-[#ffb39b]">{item.code}</span>
<span className="text-sm font-medium text-[#f4f6f8]">{item.cause}</span>
<span className="text-xs leading-relaxed text-[#a6afbd]">{item.fix}</span>
</Link>
))}
</div>
</div>
</div>
</section>
<section className="shell pb-20 pt-4 md:pb-28">
<div className="mx-auto max-w-3xl text-center">
<p className="eyebrow">Curadoria independente</p>
<h2 className="display mt-4 text-[clamp(2rem,4.5vw,3.2rem)]">
Feito para consultar no meio do projeto.
</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
O ESPDocs organiza dados públicos da Espressif e aponta sempre para a fonte oficial.
Para decisões críticas, o datasheet e o Technical Reference Manual continuam sendo a palavra final.
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href="/glossario" className="btn btn-ghost w-full sm:w-auto">
<BookOpen className="h-4 w-4" aria-hidden="true" />
Glossário
</Link>
<Link href="/sobre" className="btn btn-primary w-full sm:w-auto">
Sobre o projeto
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}
-64
View File
@@ -1,64 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Qual ESP32 escolher",
descricao: "Responda a perguntas simples sobre conectividade (Wi-Fi 6, 5GHz, Matter), energia, periféricos e segurança ou use o filtro paramétrico para encontrar o ESP32 perfeito.",
caminho: "/seletor",
keywords: ["qual ESP32 escolher", "qual ESP32 usar", "escolher microcontrolador", "ESP32 para meu projeto", "comparar ESP32"],
});
const faqs = [
{
pergunta: "Qual ESP32 escolher para iniciantes?",
resposta: "Para quem está começando no mundo Maker e IoT, o ESP32 clássico (NodeMCU/DevKitC) ou o ESP32-C3 são as melhores opções devido à vasta quantidade de bibliotecas, exemplos prontos no Arduino IDE e farta documentação em português.",
},
{
pergunta: "Qual ESP32 tem suporte a Wi-Fi 6, Bluetooth 6 e Thread/Zigbee/Matter?",
resposta: "O ESP32-C6 e o ESP32-C5 são as melhores séries para redes modernas. O ESP32-C6 oferece Wi-Fi 6 (2.4 GHz) e rádio 802.15.4 (Zigbee 3.0 / Thread / Matter). Já o ESP32-C5 é o primeiro a oferecer suporte a Wi-Fi 6 Dual-Band operando em 2.4 GHz e 5 GHz simultaneamente.",
},
{
pergunta: "Qual o ESP32 mais potente para Inteligência Artificial (TinyML) e Displays?",
resposta: "O ESP32-P4 (dual-core RISC-V a 400 MHz com extensões vetoriais de IA, interfaces MIPI-CSI/DSI para câmeras/telas e até 64 MB de PSRAM) e o ESP32-S3 (dual-core Xtensa a 240 MHz com aceleradores vetoriais para redes neurais e telas LCD RGB) são os mais velozes para IA na borda e interfaces gráficas ricas.",
},
{
pergunta: "Qual ESP32 consome menos energia para projetos a bateria?",
resposta: "Microcontroladores com arquitetura RISC-V compacta e coprocessador ULP, como o ESP32-C2, ESP32-C3 e ESP32-H2 (focado em 802.15.4 sem rádio Wi-Fi), oferecem correntes de deep sleep extremamente baixas (na faixa de 5 µA a 10 µA).",
},
];
export default function Layout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.aplicacaoWeb({
nome: "Seletor Inteligente de ESP32",
descricao: "Ferramenta interativa que analisa conectividade, consumo, periféricos e segurança para indicar a série ideal de ESP32.",
caminho: "/seletor",
})
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Seletor de ESP32", caminho: "/seletor" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
-1332
View File
File diff suppressed because it is too large. Load diff
-488
View File
@@ -1,488 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import Link from "next/link";
import Image from "next/image";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import { notFound } from "next/navigation";
import seriesData from "@/public/series.json";
import ConnectionsDiagram from "@/components/ConnectionsDiagram";
import SeriesTabMenu from "@/components/SeriesTabMenu";
import PinRestrictions from "@/components/PinRestrictions";
import {
AlertTriangle,
ArrowLeft,
ArrowRight,
ArrowUpRight,
Battery,
BookOpen,
Code,
Cpu,
Database,
ExternalLink,
FileText,
Lightbulb,
Package,
Scale,
ShieldCheck,
Sliders,
Thermometer,
Wifi,
} from "lucide-react";
export default async function SerieDetail({ params }) {
const { key } = await params;
const serie = seriesData[key];
if (!serie) {
notFound();
}
let conexoes = [];
try {
conexoes = require(`@/public/conexoes/${key}.json`);
} catch (error) {
console.log(`Arquivo de conexões não encontrado para ${key}`);
}
const seriesKeys = Object.keys(seriesData);
const currentIndex = seriesKeys.indexOf(key);
const previousKey = currentIndex > 0 ? seriesKeys[currentIndex - 1] : null;
const nextKey = currentIndex < seriesKeys.length - 1 ? seriesKeys[currentIndex + 1] : null;
const processadorSpecs = [
{ label: "Arquitetura", value: serie.arquitetura },
{ label: "Núcleos", value: serie.nucleos },
{ label: "Frequência", value: serie.frequencia },
{ label: "Coprocessador ULP", value: serie.coprocessador_ulp || "Não" },
{ label: "Aceleradores IA", value: serie.aceleradores_ia || "Não" },
];
const seg = serie.seguranca || {};
const segurancaSpecs = [
{ label: "AES", value: seg.aes || "Não" },
{ label: "SHA", value: seg.sha || "Não" },
{ label: "RSA / MPI", value: seg.rsa || "Não" },
{ label: "ECC (curvas elípticas)", value: seg.ecc || "Não" },
{ label: "ECDSA em hardware", value: seg.ecdsa || "Não" },
{ label: "HMAC", value: seg.hmac || "Não" },
{ label: "Assinatura Digital (DS)", value: seg.assinatura_digital || "Não" },
{ label: "Key Manager", value: seg.key_manager || "Não" },
{ label: "Gerador aleatório (RNG)", value: seg.rng || "Não" },
{ label: "Criptografia de flash", value: seg.criptografia_flash || "Não" },
{ label: "Secure Boot", value: seg.secure_boot || "Não" },
{ label: "Proteção contra DPA", value: seg.protecao_dpa || "Não" },
];
const ferramentasSpecs = [
{ label: "ESP-IDF mínimo", value: serie.esp_idf_minimo || "Não informado" },
{ label: "Core Arduino", value: serie.arduino_core || "Não informado" },
{ label: "Depuração", value: serie.depuracao || "Não informado" },
{ label: "Encapsulamento", value: serie.encapsulamento || "Não informado" },
{ label: "Módulos disponíveis", value: serie.modulos || "Não informado" },
];
const conectividadeSpecs = [
{ label: "Wi-Fi", value: serie.wifi || "Não" },
{ label: "Bluetooth", value: serie.bluetooth || "Não" },
{ label: "Zigbee/Thread", value: serie.zigbee_thread || "Não" },
{ label: "Matter", value: serie.matter || "Não" },
{ label: "Ethernet", value: serie.ethernet || serie.ethernet_mac || "Não" },
{ label: "CAN", value: serie.can || "Não" },
];
const memoriaSpecs = [
{ label: "SRAM", value: serie.memoria_sram },
{ label: "SRAM RTC", value: serie.memoria_sram_rtc },
{ label: "ROM", value: serie.memoria_rom },
{ label: "Flash Externa", value: serie.flash_externa },
{ label: "PSRAM Externa", value: serie.psram_externa || "Não" },
];
const perifericos = [
{ label: "GPIO", value: serie.gpio },
{ label: "ADC", value: serie.adc },
{ label: "DAC", value: serie.dac || "Não" },
{ label: "Touch", value: serie.touch || "Não" },
{ label: "UART", value: serie.uart },
{ label: "SPI", value: serie.spi },
{ label: "I2C", value: serie.i2c },
{ label: "I2S", value: serie.i2s },
{ label: "PWM", value: serie.pwm },
{ label: "USB", value: serie.usb || "Não" },
];
const interfacesEspeciais = [];
if (serie.lcd) interfacesEspeciais.push({ label: "LCD", value: serie.lcd });
if (serie.camera) interfacesEspeciais.push({ label: "Câmera", value: serie.camera });
if (serie.mipi_csi) interfacesEspeciais.push({ label: "MIPI CSI", value: serie.mipi_csi });
if (serie.mipi_dsi) interfacesEspeciais.push({ label: "MIPI DSI", value: serie.mipi_dsi });
if (serie.sdio) interfacesEspeciais.push({ label: "SDIO", value: serie.sdio });
if (serie.sensor_hall) interfacesEspeciais.push({ label: "Sensor Hall", value: serie.sensor_hall });
if (serie.sensor_temperatura) interfacesEspeciais.push({ label: "Sensor Temperatura", value: serie.sensor_temperatura });
// Consumo de Energia
const consumoEnergia = [];
if (serie.consumo_energia) {
Object.entries(serie.consumo_energia).forEach(([modo, consumo]) => {
const modoLabels = {
'active': 'Modo Ativo',
'active_cpu_240mhz': 'Ativo (CPU 240MHz)',
'active_cpu_160mhz': 'Ativo (CPU 160MHz)',
'active_wifi_tx': 'Ativo (Wi-Fi TX)',
'active_wifi_tx_peak': 'Ativo (Wi-Fi TX Pico)',
'active_wifi': 'Ativo (Wi-Fi)',
'active_wifi6': 'Ativo (Wi-Fi 6)',
'modem_sleep': 'Modem Sleep',
'modem_sleep_cpu_160mhz': 'Modem Sleep (CPU 160MHz)',
'light_sleep': 'Light Sleep',
'deep_sleep': 'Deep Sleep',
'hibernation': 'Hibernação'
};
consumoEnergia.push({
label: modoLabels[modo] || modo.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
value: consumo
});
});
}
const tabs = [
{
id: "devboard",
label: "Placa de desenvolvimento",
available: serie.placa,
content: (
<div className="card p-5 sm:p-7">
<h2 className="text-lg font-semibold text-ink">Kit de desenvolvimento oficial</h2>
<div className="mt-5 overflow-hidden rounded-xl border border-line bg-surface-2 p-4">
<Image
src={serie.placa}
alt={`Placa de desenvolvimento ${key}`}
width={1200}
height={800}
className="mx-auto h-auto max-h-[28rem] w-full rounded-lg object-contain"
priority
/>
</div>
<p className="mt-3 text-sm text-muted">Placa padrão da Espressif para a série {key}.</p>
</div>
),
},
{
id: "connections",
label: "Diagrama de conexões",
available: conexoes.length > 0,
content: (
<div className="card p-5 sm:p-7">
<div className="callout callout-warn flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
<div>
<p className="font-semibold text-ink">Este é o diagrama do chip, não da placa</p>
<p className="mt-1">
O mapa mostra as conexões do silício do <strong>{key}</strong>. Cada placa de desenvolvimento
expõe só parte delas, ou as roteia de outra forma.
</p>
</div>
</div>
<div className="mt-6">
<ConnectionsDiagram connections={conexoes} serie={serie} />
</div>
<div className="callout mt-8">
<p className="flex items-center gap-2 font-semibold text-ink">
<Lightbulb className="h-4 w-4 text-accent" aria-hidden="true" />
Quase todo pino é reconfigurável
</p>
<p className="mt-1">
A matriz de IO do {key} permite mover SPI, I2C, UART, PWM e barramentos de câmera ou display
para a maioria dos pinos digitais. Para as restrições de strapping e dos pinos analógicos,
consulte o{" "}
<a
href={`https://docs.espressif.com/projects/esp-idf/en/latest/${String(key).toLowerCase().replace("-", "")}/api-reference/peripherals/gpio.html`}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-medium text-accent underline decoration-accent/30 underline-offset-2 hover:decoration-accent"
>
guia oficial de GPIO
<ExternalLink className="h-3.5 w-3.5" aria-hidden="true" />
</a>
.
</p>
</div>
</div>
),
},
];
const secoes = [
{ id: "processador", titulo: "Processador", icon: Cpu, specs: processadorSpecs },
{ id: "conectividade", titulo: "Conectividade", icon: Wifi, specs: conectividadeSpecs },
{ id: "ferramentas", titulo: "Ferramentas e disponibilidade", icon: Package, specs: ferramentasSpecs },
{ id: "seguranca", titulo: "Segurança", icon: ShieldCheck, specs: segurancaSpecs },
{ id: "memoria", titulo: "Memória", icon: Database, specs: memoriaSpecs },
...(consumoEnergia.length > 0
? [{
id: "energia",
titulo: "Consumo de energia",
icon: Battery,
specs: consumoEnergia,
nota: "Valores típicos a 3,3 V e 25 °C. O consumo real depende do ciclo de trabalho do rádio e da frequência de clock configurada.",
}]
: []),
{ id: "perifericos", titulo: "Periféricos", icon: Sliders, specs: perifericos },
...(interfacesEspeciais.length > 0
? [{ id: "interfaces", titulo: "Interfaces especiais", icon: Sliders, specs: interfacesEspeciais }]
: []),
{
id: "temperatura",
titulo: "Limites de temperatura",
icon: Thermometer,
specs: [
{ label: "Operação", value: serie.temperatura_operacao },
{ label: "Armazenamento", value: serie.temperatura_armazenamento },
],
},
];
const fatos = [
{ label: "Processador", value: String(serie.nucleos).includes("2") ? "Dual-core" : "Single-core", detail: serie.frequencia },
{ label: "SRAM", value: serie.memoria_sram, detail: `+ ${serie.memoria_sram_rtc} de SRAM RTC` },
{ label: "GPIO", value: serie.gpio, detail: "pinos programáveis" },
{ label: "Arquitetura", value: String(serie.arquitetura).includes("RISC-V") ? "RISC-V" : "Xtensa", detail: serie.arquitetura },
];
return (
<div className="site-canvas min-h-screen">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.serie(key, serie)) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Séries", caminho: "/series" },
{ nome: serie.nome_completo, caminho: `/series/${key}` },
])),
}}
/>
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Séries", href: "/series" }, { label: key }]}
icon={Cpu}
label={serie.arquitetura}
title={key}
lede={serie.descricao}
>
{serie.datasheet ? (
<a href={serie.datasheet} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
<FileText className="h-4 w-4" aria-hidden="true" />
Datasheet oficial
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
) : (
<span className="btn btn-ghost cursor-not-allowed opacity-70" aria-disabled="true">
<FileText className="h-4 w-4" aria-hidden="true" />
Datasheet ainda não publicado
</span>
)}
{serie.guia_de_programacao && (
<a href={serie.guia_de_programacao} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
<Code className="h-4 w-4" aria-hidden="true" />
Guia de programação
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
{serie.manual_tecnico && (
<a href={serie.manual_tecnico} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
<BookOpen className="h-4 w-4" aria-hidden="true" />
Manual técnico
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
)}
</PageHero>
<section className="shell mt-10" aria-label="Resumo">
<dl className="grid grid-cols-2 gap-3 lg:grid-cols-4">
{fatos.map((fato) => (
<div key={fato.label} className="tile">
<dt className="text-xs font-medium text-muted">{fato.label}</dt>
<dd className="mt-1 font-display text-2xl font-semibold tracking-[-0.03em] text-ink">{fato.value}</dd>
<dd className="mt-0.5 text-xs text-muted">{fato.detail}</dd>
</div>
))}
</dl>
{serie.status_documentacao && (
<div className="callout callout-warn mt-4 flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
<div>
<p className="font-semibold text-ink">Documentação preliminar</p>
<p className="mt-1">{serie.status_documentacao}</p>
</div>
</div>
)}
</section>
<div className="shell mt-10">
<SeriesTabMenu tabs={tabs} />
<PinRestrictions conexoes={conexoes} serieKey={key} />
</div>
<div className="shell mt-12">
<nav
aria-label="Seções da ficha"
className="nav-pill no-scrollbar sticky top-20 z-30 flex gap-1 overflow-x-auto rounded-full p-1.5"
>
{secoes.map((secao) => (
<a key={secao.id} href={`#${secao.id}`} className="nav-link shrink-0">
{secao.titulo}
</a>
))}
</nav>
<div className="mt-8 space-y-5">
{secoes.map((secao) => (
<SpecSection key={secao.id} {...secao} />
))}
</div>
</div>
<section className="shell section">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">Pronto para prototipar o {key}?</h2>
<p className="mt-3 text-base text-muted">
Veja as placas de desenvolvimento disponíveis para a série, com USB, sensores integrados e link para a loja oficial.
</p>
</div>
<Link href="/catalogo" className="btn btn-primary shrink-0">
Ver placas
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<nav aria-label="Outras séries" className="mt-6 grid gap-3 sm:grid-cols-[1fr_auto_1fr] sm:items-center">
{previousKey ? (
<Link href={`/series/${previousKey}`} className="card card-interactive group flex items-center gap-3 px-5 py-4">
<ArrowLeft className="h-4 w-4 text-muted transition-transform group-hover:-translate-x-1" aria-hidden="true" />
<span>
<span className="block text-xs text-muted">Série anterior</span>
<span className="block font-display text-lg font-semibold text-ink">{previousKey}</span>
</span>
</Link>
) : (
<span className="hidden sm:block" />
)}
<Link href="/comparacao" className="btn btn-ghost justify-self-center">
<Scale className="h-4 w-4" aria-hidden="true" />
Comparar séries
</Link>
{nextKey ? (
<Link href={`/series/${nextKey}`} className="card card-interactive group flex items-center justify-end gap-3 px-5 py-4 text-right">
<span>
<span className="block text-xs text-muted">Próxima série</span>
<span className="block font-display text-lg font-semibold text-ink">{nextKey}</span>
</span>
<ArrowRight className="h-4 w-4 text-muted transition-transform group-hover:translate-x-1" aria-hidden="true" />
</Link>
) : (
<span className="hidden sm:block" />
)}
</nav>
</section>
</main>
<Footer />
</div>
);
}
function SpecSection({ id, titulo, icon: Icon, specs, nota }) {
return (
<section id={id} aria-labelledby={`${id}-titulo`} className="card scroll-mt-36 p-5 sm:p-7">
<h2 id={`${id}-titulo`} className="flex items-center gap-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
<span className="grid h-9 w-9 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-4 w-4" aria-hidden="true" />
</span>
{titulo}
</h2>
{nota && <p className="mt-3 text-sm text-muted">{nota}</p>}
<dl className="mt-5 grid grid-cols-2 gap-3 lg:grid-cols-3">
{specs.map((spec) => {
const negativo = /^n[ãa]o\b/i.test(String(spec.value));
return (
<div key={spec.label} className="tile">
<dt className="text-xs font-medium text-muted">{spec.label}</dt>
<dd className={`mt-1 text-sm font-semibold leading-snug ${negativo ? "text-muted" : "text-ink"}`}>{spec.value}</dd>
</div>
);
})}
</dl>
</section>
);
}
export async function generateMetadata({ params }) {
const { key } = await params;
const serie = seriesData[key];
if (!serie) {
return { title: "Série não encontrada", robots: { index: false, follow: false } };
}
// A descrição usa as especificações reais em vez de texto genérico: é o que
// aparece no resultado de busca e o que faz alguém clicar.
const radio = [
String(serie.wifi).startsWith("Não") ? null : serie.wifi.split(" (")[0],
String(serie.bluetooth).startsWith("Não") ? null : serie.bluetooth.split(" (")[0],
serie.zigbee_thread && !String(serie.zigbee_thread).startsWith("Não") ? "802.15.4" : null,
].filter(Boolean).join(", ");
const descricao =
`${serie.nome_completo}: ${serie.arquitetura}, ${serie.frequencia.replace("Até ", "até ")}, ` +
`${serie.memoria_sram} de SRAM e ${serie.gpio} GPIOs` +
(radio ? `. Rádio: ${radio}` : "") +
`. Pinagem completa, periféricos, segurança em hardware e pinos com restrição, em português.`;
// A pinagem da placa é a melhor prévia possível para uma série: quem
// compartilha o link já mostra o diagrama. Séries sem placa publicada caem
// na imagem padrão do site.
// Definir openGraph explicitamente impede a herança automática da imagem do
// site, então séries sem placa publicada (o H4) precisam do fallback aqui.
const imagem = serie.placa
? [{ url: serie.placa, width: 1600, height: 1091, alt: `Pinagem do ${serie.nome_completo}` }]
: [{ url: "/opengraph-image.png", width: 1200, height: 630, alt: "ESPDocs" }];
const meta = {
...paginaMeta({
titulo: `${serie.nome_completo}: especificações e pinagem`,
descricao,
caminho: `/series/${key}`,
tipo: "article",
keywords: [
serie.nome_completo, `${serie.nome_completo} pinout`,
`${serie.nome_completo} datasheet`, `${serie.nome_completo} especificações`,
`${serie.nome_completo} português`, "ESP32", "Espressif", "microcontrolador",
],
}),
other: { "article:section": "Séries ESP32" },
};
meta.openGraph = { ...meta.openGraph, images: imagem };
meta.twitter = { ...meta.twitter, images: imagem };
return meta;
}
export async function generateStaticParams() {
return Object.keys(seriesData).map((key) => ({
key: key,
}));
}
-46
View File
@@ -1,46 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
export const metadata = paginaMeta({
titulo: "Séries ESP32",
descricao: "As 12 séries de ESP32 lado a lado: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 e H4. Arquitetura, memória, rádio, periféricos e pinagem de cada uma, em português.",
caminho: "/series",
keywords: ["séries ESP32", "modelos de ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "diferença entre ESP32"],
});
metadata.title = { default: "Séries ESP32", template: "%s · ESPDocs" };
const faqs = [
{
pergunta: "Quantas séries de ESP32 existem atualmente?",
resposta: "Atualmente o ecossistema Espressif conta com 12 séries principais: ESP32 clássico, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 e ESP32-H4.",
},
{
pergunta: "Quais são as séries mais recentes da Espressif?",
resposta: "As séries mais recentes incluem o ESP32-P4 (focado em alto desempenho com dual-core RISC-V a 400 MHz), o ESP32-C5 (primeiro chip com Wi-Fi dual-band 2.4/5 GHz da Espressif) e o ESP32-C61 (Wi-Fi 6 e Bluetooth 6 de baixo custo).",
},
];
export default function Layout({ children }) {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Séries ESP32", caminho: "/series" },
])
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd.perguntas(faqs)),
}}
/>
{children}
</>
);
}
-154
View File
@@ -1,154 +0,0 @@
"use client";
import { useMemo, useState } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Link from "next/link";
import seriesData from "@/public/series.json";
import {
AlertTriangle,
ArrowRight,
ArrowUpRight,
Compass,
Home,
Scale,
ShieldCheck,
Sparkles,
} from "lucide-react";
const FILTROS = [
{ id: "todas", rotulo: "Todas", testa: () => true },
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Sim" },
{ id: "ia", rotulo: "Aceleração de IA", testa: (s) => Boolean(s.aceleradores_ia) },
];
/** Marcador de segurança: o recurso que diferencia a série, não o que todas têm. */
function nivelSeguranca(serie) {
const seg = serie.seguranca || {};
if (seg.key_manager === "Sim") return "Key Manager";
if (String(seg.ecdsa).startsWith("Sim")) return "ECDSA em hardware";
if (String(seg.ecc).startsWith("Sim")) return "ECC em hardware";
if (String(seg.aes).startsWith("AES")) return "AES + SHA";
return "Só SHA";
}
const sim = (v) => !String(v).includes("Não");
export default function Series() {
const [filtro, setFiltro] = useState("todas");
const todas = Object.entries(seriesData);
const ativo = FILTROS.find((f) => f.id === filtro);
const series = useMemo(() => todas.filter(([, s]) => ativo.testa(s)), [todas, ativo]);
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Séries" }]}
icon={Compass}
label={`${todas.length} famílias da Espressif`}
title="Séries ESP32"
lede="Cada série foi desenhada para um tipo de projeto, do sensor a bateria ao acelerador de IA. Abra a ficha para ver pinagem, periféricos e segurança."
/>
<section className="shell pt-10 sm:pt-12" aria-label="Lista de séries">
<div role="group" aria-label="Filtrar séries" className="flex flex-wrap gap-2">
{FILTROS.map((f) => (
<button key={f.id} type="button" aria-pressed={filtro === f.id} onClick={() => setFiltro(f.id)} className="chip-btn">
{f.rotulo}
</button>
))}
</div>
<p role="status" aria-live="polite" className="mt-4 text-sm text-muted">
{series.length} {series.length === 1 ? "série" : "séries"}
</p>
<div className="mt-4 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{series.map(([key, serie]) => {
const riscv = serie.arquitetura.includes("RISC-V");
const fatos = [
["Núcleos", serie.nucleos],
["Frequência", serie.frequencia],
["SRAM", serie.memoria_sram],
["Wi-Fi", sim(serie.wifi) ? "Sim" : "Não"],
["Bluetooth", serie.bluetooth === "Não" ? "Não" : "Sim"],
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
].filter(Boolean);
return (
<Link key={key} href={`/series/${key}`} className="card card-interactive group flex flex-col p-5 sm:p-6">
<div className="flex items-start justify-between gap-3">
<h2 className="font-display text-2xl font-semibold tracking-[-0.035em] text-ink">{key}</h2>
<span className="chip">{riscv ? "RISC-V" : "Xtensa"}</span>
</div>
<p className="mt-2 line-clamp-2 min-h-[2.9rem] text-sm leading-relaxed text-muted">{serie.descricao}</p>
<dl className="mt-5 divide-y divide-line border-y border-line text-sm">
{fatos.map(([rotulo, valor]) => (
<div key={rotulo} className="flex items-baseline justify-between gap-4 py-2">
<dt className="text-muted">{rotulo}</dt>
<dd className={`text-right font-medium ${valor === "Não" ? "text-muted" : "text-ink"}`}>{valor}</dd>
</div>
))}
</dl>
<ul className="mt-4 flex flex-1 flex-wrap content-start gap-1.5">
{serie.aceleradores_ia && (
<li className="chip chip-accent">
<Sparkles className="h-3 w-3" aria-hidden="true" />
Aceleradores de IA
</li>
)}
<li className="chip">
<ShieldCheck className="h-3 w-3 text-accent" aria-hidden="true" />
{nivelSeguranca(serie)}
</li>
{serie.matter === "Sim" && (
<li className="chip">
<Home className="h-3 w-3 text-accent" aria-hidden="true" />
Matter
</li>
)}
{serie.status_documentacao && (
<li className="chip">
<AlertTriangle className="h-3 w-3 text-gold" aria-hidden="true" />
Documentação preliminar
</li>
)}
</ul>
<span className="mt-5 inline-flex items-center gap-1 text-sm font-medium text-accent">
Abrir ficha
<ArrowUpRight className="h-4 w-4 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
);
})}
</div>
</section>
<section className="shell section">
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">Ficou em dúvida entre duas séries?</h2>
<p className="mt-3 text-base text-muted">
O comparador coloca até quatro modelos lado a lado: núcleos, rádio, memória, periféricos e segurança.
</p>
</div>
<Link href="/comparacao" className="btn btn-primary shrink-0">
<Scale className="h-4 w-4" aria-hidden="true" />
Comparar séries
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
</main>
<Footer />
</div>
);
}
+55 -28
View File
@@ -1,51 +1,78 @@
import seriesData from "@/public/series.json";
import frameworksData from "@/public/frameworks.json";
import { SITE } from "@/lib/seo";
import { ENABLED_LOCALES, getLocalizedHref } from "@/i18n/links";
const LANG_MAP = {
pt: "pt-BR",
en: "en",
es: "es-419",
fr: "fr",
de: "de",
"zh-CN": "zh-CN",
};
/**
* Sitemap gerado a partir dos próprios dados do site.
*
* Antes não existia sitemap nenhum, então o Google só chegava às páginas de
* série e de framework se topasse com um link. Como são geradas a partir de
* JSON, uma série nova entra aqui sozinha.
* Sitemap gerado a partir dos próprios dados do site e dos idiomas ativos.
* Inclui URLs apenas para ENABLED_LOCALES, com hreflang/alternates correspondentes.
* O livro só entra para a versão em português.
*/
export default function sitemap() {
// Usar uma data de revisão estável evita que todo deploy force o Googlebot
// a reprocessar páginas idênticas ao mesmo tempo.
const dataRevisao = new Date("2026-08-25T00:00:00.000Z");
const fixas = [
{ caminho: "", prioridade: 1.0, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/series", prioridade: 0.9, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/comparacao", prioridade: 0.9, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/diagnostico", prioridade: 0.9, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/seletor", prioridade: 0.8, frequencia: "monthly", lastModified: dataRevisao },
{ caminho: "/frameworks", prioridade: 0.8, frequencia: "monthly", lastModified: dataRevisao },
{ caminho: "/componentes", prioridade: 0.8, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/livro", prioridade: 0.7, frequencia: "monthly", lastModified: dataRevisao },
{ caminho: "/glossario", prioridade: 0.7, frequencia: "monthly", lastModified: dataRevisao },
{ caminho: "/catalogo", prioridade: 0.6, frequencia: "weekly", lastModified: dataRevisao },
{ caminho: "/sobre", prioridade: 0.4, frequencia: "yearly", lastModified: dataRevisao },
{ rota: "", prioridade: 1.0, frequencia: "weekly" },
{ rota: "/series", prioridade: 0.9, frequencia: "weekly" },
{ rota: "/comparacao", prioridade: 0.9, frequencia: "weekly" },
{ rota: "/diagnostico", prioridade: 0.9, frequencia: "weekly" },
{ rota: "/seletor", prioridade: 0.8, frequencia: "monthly" },
{ rota: "/frameworks", prioridade: 0.8, frequencia: "monthly" },
{ rota: "/componentes", prioridade: 0.8, frequencia: "weekly" },
{ rota: "/livro", prioridade: 0.7, frequencia: "monthly", apenasPt: true },
{ rota: "/glossario", prioridade: 0.7, frequencia: "monthly" },
{ rota: "/catalogo", prioridade: 0.6, frequencia: "weekly" },
{ rota: "/sobre", prioridade: 0.4, frequencia: "yearly" },
];
const series = Object.keys(seriesData).map((chave) => ({
caminho: `/series/${chave}`,
rota: `/series/${chave}`,
prioridade: 0.9,
frequencia: "monthly",
lastModified: dataRevisao,
}));
const frameworks = Object.keys(frameworksData).map((chave) => ({
caminho: `/frameworks/${encodeURIComponent(chave)}`,
rota: `/frameworks/${encodeURIComponent(chave)}`,
prioridade: 0.6,
frequencia: "monthly",
lastModified: dataRevisao,
}));
return [...fixas, ...series, ...frameworks].map(({ caminho, prioridade, frequencia, lastModified }) => ({
url: `${SITE.url}${caminho}`,
lastModified,
changeFrequency: frequencia,
priority: prioridade,
}));
const todasRotas = [...fixas, ...series, ...frameworks];
const entries = [];
for (const item of todasRotas) {
for (const loc of ENABLED_LOCALES) {
if (item.apenasPt && loc !== "pt") continue;
const href = getLocalizedHref(`/pt${item.rota}`, loc);
const url = `${SITE.url}${href}`;
const languages = {};
for (const l of ENABLED_LOCALES) {
if (item.apenasPt && l !== "pt") continue;
languages[LANG_MAP[l] || l] = `${SITE.url}${getLocalizedHref(`/pt${item.rota}`, l)}`;
}
entries.push({
url,
lastModified: dataRevisao,
changeFrequency: item.frequencia,
priority: item.prioridade,
alternates: {
languages,
},
});
}
}
return entries;
}
-175
View File
@@ -1,175 +0,0 @@
import { paginaMeta, jsonLd } from "@/lib/seo";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PageHero from "@/components/PageHero";
import Image from "next/image";
import { ArrowUpRight, Code, Globe, GitCompare, Info, Languages } from "lucide-react";
const GITHUB = "https://github.com/lucasrguerra/ESPDocs";
function GithubMark({ className }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12 .5a12 12 0 00-3.8 23.4c.6.1.8-.3.8-.6v-2.1c-3.3.7-4-1.6-4-1.6-.5-1.2-1.2-1.5-1.2-1.5-1-.7.1-.7.1-.7 1.1.1 1.7 1.1 1.7 1.1 1 .1 1.6-.7 1.9-1 .1-.8.4-1.3.8-1.6-2.6-.3-5.3-1.3-5.3-5.8 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.6.1-3.3 0 0 1-.3 3.3 1.2a11.4 11.4 0 016 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 3 .1 3.3.8.8 1.2 1.9 1.2 3.1 0 4.5-2.7 5.5-5.3 5.8.5.4.9 1.1.9 2.2v3.2c0 .3.2.7.8.6A12 12 0 0012 .5z" />
</svg>
);
}
export const metadata = paginaMeta({
titulo: "Sobre o projeto",
descricao: "O ESPDocs é uma plataforma independente que reúne a documentação do ecossistema ESP32 em português brasileiro. Saiba como o projeto nasceu e como contribuir.",
caminho: "/sobre",
keywords: ["ESPDocs", "documentação ESP32 português", "projeto open source ESP32"],
});
export default function Sobre() {
const features = [
{ icon: Languages, title: "Em português", desc: "Dados técnicos organizados e apresentados em português do Brasil." },
{ icon: GitCompare, title: "Comparações visuais", desc: "Tabelas e diagramas para escolher a série certa sem abrir dez datasheets." },
{ icon: Globe, title: "Acesso centralizado", desc: "Links diretos para a documentação oficial, repositórios e exemplos." },
{ icon: Code, title: "Código aberto", desc: "Contribuições são bem-vindas no GitHub." },
];
return (
<div className="site-canvas min-h-screen">
{/* Metadados E-E-A-T de autoria e organização para o Google */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.paginaSobre()) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Sobre o Projeto", caminho: "/sobre" },
])
),
}}
/>
<Header />
<main id="conteudo">
<PageHero
trail={[{ label: "Sobre" }]}
icon={Info}
label="Projeto independente"
title="Sobre o ESPDocs"
lede="Uma plataforma não oficial, em português, que organiza as informações técnicas do ESP32 e leva você à documentação oficial da Espressif. Feita para a comunidade de hardware livre."
>
<a href={GITHUB} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
<GithubMark className="h-4 w-4" />
Ver o repositório
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</PageHero>
<div className="shell section grid grid-cols-1 gap-10 pt-12 sm:pt-16 lg:grid-cols-[1fr_22rem] lg:gap-14">
<div className="min-w-0 max-w-3xl space-y-12">
<section aria-labelledby="missao">
<h2 id="missao" className="section-title">Missão</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
Facilitar o acesso e a compreensão do ecossistema ESP32 com uma interface em português que organiza
especificações, compara séries, apresenta frameworks e centraliza os links da documentação oficial.
O objetivo é economizar o seu tempo no desenvolvimento de firmware e IoT.
</p>
</section>
<section aria-labelledby="porque">
<h2 id="porque" className="section-title">Por que o ESPDocs existe</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
As informações sobre os ESP32 costumam estar espalhadas entre datasheets densos, manuais de referência
(TRM) e repositórios secundários, tudo em inglês. O ESPDocs condensa e estrutura esses dados para a
triagem rápida, antes de você aprofundar na engenharia oficial.
</p>
<ul className="mt-6 grid gap-3 sm:grid-cols-2">
{features.map(({ icon: Icon, title, desc }) => (
<li key={title} className="card flex items-start gap-4 p-5">
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<div>
<h3 className="font-semibold text-ink">{title}</h3>
<p className="mt-1 text-sm leading-relaxed text-muted">{desc}</p>
</div>
</li>
))}
</ul>
</section>
<section aria-labelledby="contribuir">
<h2 id="contribuir" className="section-title">Como contribuir</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
Correções de tradução, ajustes em tabelas e novos exemplos de código são muito bem-vindos. O projeto
cresce com a comunidade.
</p>
<ol className="mt-6 space-y-3">
{[
"Faça o fork do repositório no GitHub.",
"Implemente as melhorias e confira as referências técnicas oficiais.",
"Abra um Pull Request descrevendo os ajustes feitos.",
].map((passo, i) => (
<li key={passo} className="card flex items-center gap-4 px-5 py-4">
<span className="grid h-8 w-8 shrink-0 place-items-center rounded-full bg-ink text-sm font-semibold text-canvas" aria-hidden="true">
{i + 1}
</span>
<span className="text-sm text-ink-soft sm:text-base">{passo}</span>
</li>
))}
</ol>
</section>
<section aria-labelledby="acessibilidade">
<h2 id="acessibilidade" className="section-title">Acessibilidade</h2>
<p className="mt-4 text-base leading-relaxed text-muted">
O ESPDocs prioriza a legibilidade, o contraste alto (nível AAA da WCAG) e a navegação completa por
teclado. Se encontrar alguma barreira de leitura ou navegação, abra uma issue no repositório.
</p>
</section>
</div>
<aside className="space-y-5 lg:sticky lg:top-28 lg:self-start" aria-label="Autor e aviso legal">
<div className="panel p-6 sm:p-7">
<div className="flex items-center gap-4">
<span className="grid h-16 w-16 shrink-0 place-items-center rounded-2xl border border-line bg-white">
<Image src="/logo.png" alt="" aria-hidden="true" width={48} height={48} className="h-12 w-12 object-contain" />
</span>
<div>
<h2 className="font-display text-lg font-semibold text-ink">Lucas Rayan Guerra</h2>
<p className="text-sm text-muted">Criador do Ciência Embarcada</p>
</div>
</div>
<div className="mt-5 space-y-3 text-sm leading-relaxed text-muted">
<p>
Técnico em Desenvolvimento de Sistemas, estudante de Ciência da Computação na UFRPE e pesquisador de
Blockchain e Criptografia.
</p>
<p>
Diretor de Software na Semine AgriTech e palestrante em eventos como o REC&apos;n&apos;Play, compartilha
conteúdo sobre hardware, IoT e cibersegurança.
</p>
</div>
<a href="https://cienciaembarcada.com.br" target="_blank" rel="noopener noreferrer" className="btn btn-ghost mt-6 w-full">
Visitar o Ciência Embarcada
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</div>
<div className="callout callout-warn">
<p className="font-semibold text-ink">Aviso legal</p>
<p className="mt-1">
O ESPDocs é um agregador e organizador. Os manuais e repositórios referenciados pertencem à Espressif
Systems. Em projetos críticos ou comerciais, consulte sempre a documentação oficial.
</p>
</div>
</aside>
</div>
</main>
<Footer />
</div>
);
}
+122 -7
View File
@@ -1,8 +1,110 @@
"use client";
import { ArrowUpRight, Award, Check, CircleHelp } from "lucide-react";
import { usePathname } from "next/navigation";
const HEADER_MAP_EN = {
"Nome": "Name",
"Descrição": "Description",
"Série": "Series",
"Loja Oficial": "Official Store",
"Fabricante": "Manufacturer",
"Processador": "Processor",
"Memória Flash": "Flash Memory",
"PSRAM": "PSRAM",
"Conector USB": "USB Connector",
"Interface USB": "USB Interface",
"Antena": "Antenna",
"Bateria": "Battery",
"Display": "Display",
"Sensores": "Sensors",
"Botões": "Buttons",
"LEDs": "LEDs",
};
const HEADER_MAP_ES = {
"Nome": "Nombre",
"Descrição": "Descripción",
"Série": "Serie",
"Loja Oficial": "Tienda oficial",
"Fabricante": "Fabricante",
"Processador": "Procesador",
"Memória Flash": "Memoria flash",
"PSRAM": "PSRAM",
"Conector USB": "Conector USB",
"Interface USB": "Interfaz USB",
"Antena": "Antena",
"Bateria": "Batería",
"Display": "Pantalla",
"Sensores": "Sensores",
"Botões": "Botones",
"LEDs": "LEDs",
};
const HEADER_MAP_FR = {
"Nome": "Nom",
"Descrição": "Description",
"Série": "Série",
"Loja Oficial": "Boutique officielle",
"Fabricante": "Fabricant",
"Processador": "Processeur",
"Memória Flash": "Mémoire flash",
"PSRAM": "PSRAM",
"Conector USB": "Connecteur USB",
"Interface USB": "Interface USB",
"Antena": "Antenne",
"Bateria": "Batterie",
"Display": "Écran",
"Sensores": "Capteurs",
"Botões": "Boutons",
"LEDs": "LEDs",
};
const HEADER_MAP_DE = {
"Nome": "Name",
"Descrição": "Beschreibung",
"Série": "Serie",
"Loja Oficial": "Offizieller Shop",
"Fabricante": "Hersteller",
"Processador": "Prozessor",
"Memória Flash": "Flash-Speicher",
"PSRAM": "PSRAM",
"Conector USB": "USB-Anschluss",
"Interface USB": "USB-Schnittstelle",
"Antena": "Antenne",
"Bateria": "Batterie",
"Display": "Display",
"Sensores": "Sensoren",
"Botões": "Taster",
"LEDs": "LEDs",
};
const HEADER_MAP_ZH = {
"Nome": "名称",
"Descrição": "描述",
"Série": "系列",
"Loja Oficial": "官方商店",
"Fabricante": "制造商",
"Processador": "处理器",
"Memória Flash": "闪存",
"PSRAM": "PSRAM",
"Conector USB": "USB 接口",
"Interface USB": "USB 接口类型",
"Antena": "天线",
"Bateria": "电池",
"Display": "显示屏",
"Sensores": "传感器",
"Botões": "按键",
"LEDs": "LED",
};
export default function BoardCard({ board }) {
const pathname = usePathname() || "";
const isEn = pathname === "/en" || pathname.startsWith("/en/");
const isEs = pathname === "/es" || pathname.startsWith("/es/");
const isFr = pathname === "/fr" || pathname.startsWith("/fr/");
const isDe = pathname === "/de" || pathname.startsWith("/de/");
const isZh = pathname === "/zh-CN" || pathname.startsWith("/zh-CN/");
const mainFields = ["Nome", "Link", "Imagem", "Loja Oficial"];
const technicalFields = Object.keys(board).filter((key) => !mainFields.includes(key) && board[key]);
@@ -24,20 +126,31 @@ export default function BoardCard({ board }) {
{lojaOficial && (
<span className="chip chip-accent mb-3 w-fit">
<Award className="h-3.5 w-3.5" aria-hidden="true" />
Loja oficial
{isEn ? "Official store" : isEs ? "Tienda oficial" : isFr ? "Boutique officielle" : isZh ? "官方商店" : isDe ? "Offizieller Shop" : "Loja oficial"}
</span>
)}
<h3 className="line-clamp-2 font-display text-lg font-semibold leading-snug tracking-[-0.02em] text-ink">
{board.Nome || "Placa genérica"}
{board.Nome || (isEn ? "Generic board" : isEs ? "Placa genérica" : isFr ? "Carte générique" : isZh ? "通用开发板" : isDe ? "Generisches Board" : "Placa genérica")}
</h3>
{recursos.length > 0 && (
<div className="mt-4">
<p className="text-xs font-medium text-muted">Recursos embarcados</p>
<p className="text-xs font-medium text-muted">
{isEn ? "On-board features" : isEs ? "Recursos integrados" : isFr ? "Fonctionnalités intégrées" : isZh ? "板载资源" : isDe ? "Integrierte Funktionen" : "Recursos embarcados"}
</p>
<ul className="mt-2 flex flex-wrap gap-1.5">
{recursos.map((campo) => {
const opcional = valor(campo) === "opcional";
const label = isEn
? (HEADER_MAP_EN[campo] || campo)
: isEs
? (HEADER_MAP_ES[campo] || campo)
: isFr
? (HEADER_MAP_FR[campo] || campo)
: isZh ? (HEADER_MAP_ZH[campo] || campo) : isDe
? (HEADER_MAP_DE[campo] || campo)
: campo;
return (
<li key={campo} className={`chip ${opcional ? "text-gold" : "text-ink-soft"}`}>
{opcional ? (
@@ -45,8 +158,8 @@ export default function BoardCard({ board }) {
) : (
<Check className="h-3 w-3 text-ok" aria-hidden="true" />
)}
{campo}
{opcional && <span className="sr-only"> (opcional)</span>}
{label}
{opcional && <span className="sr-only">{isEn ? " (optional)" : isEs ? " (opcional)" : isFr ? " (optionnel)" : isZh ? "(可选)" : isDe ? " (optional)" : " (opcional)"}</span>}
</li>
);
})}
@@ -56,9 +169,11 @@ export default function BoardCard({ board }) {
{board.Link && (
<a href={board.Link} target="_blank" rel="noopener noreferrer" className="btn btn-primary mt-6 w-full">
Ver no AliExpress
{isEn ? "View on AliExpress" : isEs ? "Ver en AliExpress" : isFr ? "Voir sur AliExpress" : isZh ? "在 AliExpress 查看" : isDe ? "Auf AliExpress ansehen" : "Ver no AliExpress"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> (abre em nova aba)</span>
<span className="sr-only">
{isEn ? " (opens in new tab)" : isEs ? " (abre en una pestaña nueva)" : isFr ? " (ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? " (öffnet in neuem Tab)" : " (abre em nova aba)"}
</span>
</a>
)}
</div>
+157 -16
View File
@@ -2,8 +2,17 @@
import { useEffect, useState } from "react";
import { Check, Copy, ExternalLink } from "lucide-react";
import { usePathname } from "next/navigation";
export default function CodeExample({ framework }) {
const pathname = usePathname() || "";
const isEn = pathname === "/en" || pathname.startsWith("/en/");
const isEs = pathname === "/es" || pathname.startsWith("/es/");
const isFr = pathname === "/fr" || pathname.startsWith("/fr/");
const isDe = pathname === "/de" || pathname.startsWith("/de/");
const isZh = pathname === "/zh-CN" || pathname.startsWith("/zh-CN/");
const loc = isEn ? "en" : isEs ? "es" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const examplesUrl = framework?.exemplos;
const [sample, setSample] = useState("");
@@ -20,18 +29,42 @@ export default function CodeExample({ framework }) {
const exemploPath = framework.exemplo;
if (!exemploPath) {
setSample(`// Exemplos completos: ${examplesUrl || "ver repositório"}\n`);
setSample(
isEn
? `// Full examples: ${examplesUrl || "see repository"}\n`
: isEs
? `// Ejemplos completos: ${examplesUrl || "ver repositorio"}\n`
: isFr
? `// Exemples complets : ${examplesUrl || "voir le dépôt"}\n`
: isZh ? `// 完整示例:${examplesUrl || "见代码仓库"}\n` : isDe
? `// Vollständige Beispiele: ${examplesUrl || "Repository ansehen"}\n`
: `// Exemplos completos: ${examplesUrl || "ver repositório"}\n`
);
return;
}
const url = exemploPath.startsWith("/") ? exemploPath : `/${exemploPath}`;
// Se locale for diferente de pt, busca primeiro em /exemplos/<loc>/
let url = exemploPath.startsWith("/") ? exemploPath : `/${exemploPath}`;
if (loc !== "pt" && url.startsWith("/exemplos/") && !url.startsWith(`/exemplos/${loc}/`)) {
url = url.replace("/exemplos/", `/exemplos/${loc}/`);
}
let cancelled = false;
setLoading(true);
fetch(url)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
if (!res.ok) {
// Fallback para o arquivo original se não achar a versão traduzida
const fallbackUrl = exemploPath.startsWith("/") ? exemploPath : `/${exemploPath}`;
if (fallbackUrl !== url) {
return fetch(fallbackUrl).then((r2) => {
if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
return r2.text();
});
}
throw new Error(`HTTP ${res.status}`);
}
return res.text();
})
.then((text) => {
@@ -39,14 +72,55 @@ export default function CodeExample({ framework }) {
if (text && text.trim().length > 0) {
setSample(text);
} else {
setSample("// O arquivo de exemplo está vazio. Consulte o repositório oficial.\n");
setError("arquivo vazio");
setSample(
isEn
? "// The example file is empty. Refer to the official repository.\n"
: isEs
? "// El archivo de ejemplo está vacío. Consulte el repositorio oficial.\n"
: isFr
? "// Le fichier d'exemple est vide. Consultez le dépôt officiel.\n"
: isZh ? "// 示例文件为空,请查阅官方代码仓库。\n" : isDe
? "// Die Beispieldatei ist leer. Bitte konsultieren Sie das offizielle Repository.\n"
: "// O arquivo de exemplo está vazio. Consulte o repositório oficial.\n"
);
setError(
isEn
? "empty file"
: isEs
? "archivo vacío"
: isFr
? "fichier vide"
: isZh ? "文件为空" : isDe
? "leere Datei"
: "arquivo vazio"
);
}
})
.catch((err) => {
if (cancelled) return;
setSample("// Não foi possível carregar o exemplo.\n// Consulte o repositório oficial para exemplos completos.\n");
setError(err.message || "falha ao carregar");
setSample(
isEn
? "// Could not load example.\n// Refer to official repository for complete examples.\n"
: isEs
? "// No fue posible cargar el ejemplo.\n// Consulte el repositorio oficial para ver los ejemplos completos.\n"
: isFr
? "// Impossible de charger l'exemple.\n// Consultez le dépôt officiel pour des exemples complets.\n"
: isZh ? "// 无法加载示例。\n// 完整示例请查阅官方代码仓库。\n" : isDe
? "// Beispiel konnte nicht geladen werden.\n// Vollständige Beispiele finden Sie im offiziellen Repository.\n"
: "// Não foi possível carregar o exemplo.\n// Consulte o repositório oficial para exemplos completos.\n"
);
setError(
err.message ||
(isEn
? "load failure"
: isEs
? "fallo al cargar"
: isFr
? "échec du chargement"
: isZh ? "加载失败" : isDe
? "Ladefehler"
: "falha ao carregar")
);
})
.finally(() => {
if (!cancelled) setLoading(false);
@@ -55,7 +129,7 @@ export default function CodeExample({ framework }) {
return () => {
cancelled = true;
};
}, [framework?.exemplo, framework?.exemplos]);
}, [framework?.exemplo, framework?.exemplos, isEn, isEs, isFr, isDe, loc]);
const lines = (sample || "").replace(/\n$/, "").split("\n");
@@ -71,20 +145,54 @@ export default function CodeExample({ framework }) {
<div className="card p-5 sm:p-7">
<div className="flex flex-wrap items-start justify-between gap-4">
<div>
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">Exemplo de código</h2>
<p className="mt-1 text-sm text-muted">Trecho de partida em {framework?.linguagem}. Ajuste pinos e configuração à sua placa.</p>
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">
{isEn
? "Code example"
: isEs
? "Ejemplo de código"
: isFr
? "Exemple de code"
: isZh ? "代码示例" : isDe
? "Codebeispiel"
: "Exemplo de código"}
</h2>
<p className="mt-1 text-sm text-muted">
{isEn
? `Starter snippet in ${framework?.linguagem}. Adjust pins and configuration for your board.`
: isEs
? `Fragmento de inicio en ${framework?.linguagem}. Ajuste los pines y la configuración para su placa.`
: isFr
? `Extrait de départ en ${framework?.linguagem}. Adaptez les broches et la configuration à votre carte.`
: isZh ? `${framework?.linguagem} 的起始代码片段,请根据你的开发板调整引脚和配置。` : isDe
? `Startbeispiel in ${framework?.linguagem}. Passen Sie Pins und Konfiguration an Ihr Board an.`
: `Trecho de partida em ${framework?.linguagem}. Ajuste pinos e configuração à sua placa.`}
</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<button type="button" onClick={handleCopy} className="btn btn-ghost btn-sm">
{copied ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
<span role="status">{copied ? "Copiado" : "Copiar"}</span>
<span role="status">
{copied
? (isEn ? "Copied" : isEs ? "Copiado" : isFr ? "Copié" : isZh ? "已复制" : isDe ? "Kopiert" : "Copiado")
: (isEn ? "Copy" : isEs ? "Copiar" : isFr ? "Copier" : isZh ? "复制" : isDe ? "Kopieren" : "Copiar")}
</span>
</button>
{examplesUrl && (
<a href={examplesUrl} target="_blank" rel="noopener noreferrer" className="btn btn-ghost btn-sm">
Mais exemplos
{isEn ? "More examples" : isEs ? "Más ejemplos" : isFr ? "Plus d'exemples" : isZh ? "更多示例" : isDe ? "Weitere Beispiele" : "Mais exemplos"}
<ExternalLink className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> (abre em nova aba)</span>
<span className="sr-only">
{isEn
? " (opens in new tab)"
: isEs
? " (abre en una pestaña nueva)"
: isFr
? " (ouvre un nouvel onglet)"
: isZh ? "(在新标签页打开)" : isDe
? " (öffnet in neuem Tab)"
: " (abre em nova aba)"}
</span>
</a>
)}
</div>
@@ -93,9 +201,34 @@ export default function CodeExample({ framework }) {
<div className="code-panel mt-5" aria-busy={loading}>
<div className="flex items-center justify-between border-b border-white/10 px-4 py-2.5 text-xs text-[#a6afbd]">
<span className="font-mono">{framework?.nome}</span>
<span>{loading ? "Carregando exemplo…" : framework?.linguagem}</span>
<span>
{loading
? (isEn
? "Loading example…"
: isEs
? "Cargando ejemplo…"
: isFr
? "Chargement de l'exemple…"
: isZh ? "正在加载示例…" : isDe
? "Beispiel wird geladen…"
: "Carregando exemplo…")
: framework?.linguagem}
</span>
</div>
<pre tabIndex={0} aria-label={`Código de exemplo em ${framework?.linguagem}`}>
<pre
tabIndex={0}
aria-label={
isEn
? `Code example in ${framework?.linguagem}`
: isEs
? `Código de ejemplo en ${framework?.linguagem}`
: isFr
? `Exemple de code en ${framework?.linguagem}`
: isZh ? `${framework?.linguagem} 示例代码` : isDe
? `Codebeispiel in ${framework?.linguagem}`
: `Código de exemplo em ${framework?.linguagem}`
}
>
<code>
{lines.map((line, idx) => (
<span key={idx} className="flex">
@@ -109,7 +242,15 @@ export default function CodeExample({ framework }) {
{error && (
<p role="alert" className="callout callout-warn mt-4">
Não foi possível carregar o exemplo local ({error}). Use “Mais exemplos” para ver o código oficial.
{isEn
? `Could not load local example (${error}). Use “More examples” to view official code.`
: isEs
? `No se pudo cargar el ejemplo local (${error}). Utilice “Más ejemplos” para ver el código oficial.`
: isFr
? `Impossible de charger l'exemple local (${error}). Utilisez « Plus d'exemples » pour consulter le code officiel.`
: isZh ? `无法加载本地示例(${error})。请使用“更多示例”查看官方代码。` : isDe
? `Lokales Beispiel konnte nicht geladen werden (${error}). Nutzen Sie „Weitere Beispiele“, um den offiziellen Code anzusehen.`
: `Não foi possível carregar o exemplo local (${error}). Use “Mais exemplos” para ver o código oficial.`}
</p>
)}
</div>
+365 -42
View File
@@ -1,7 +1,8 @@
"use client";
import { useState, useEffect, useMemo, useRef } from "react";
import { useState, useEffect, useMemo, useRef, Suspense } from "react";
import { createPortal } from "react-dom";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { AlertTriangle, CheckCircle, List, Grid, Search, Sliders, X, Zap } from "lucide-react";
/*
@@ -32,6 +33,120 @@ const FILTER_CATEGORIES = [
{ id: "Antena", name: "Antena", color: "#06b6d4" }, // cyan
];
const FILTER_CATEGORIES_EN = [
{ id: "All", name: "All", color: "#8b5cf6" },
{ id: "GND", name: "Ground (GND)", color: "#64748b" },
{ id: "Power", name: "Power", color: "#ef4444" },
{ id: "GPIO", name: "GPIO", color: "#22c55e" },
{ id: "Low Power", name: "LP GPIO", color: "#f59e0b" },
{ id: "ADC", name: "ADC", color: "#ec4899" },
{ id: "DAC", name: "DAC", color: "#a855f7" },
{ id: "Touch", name: "Touch", color: "#06b6d4" },
{ id: "UART", name: "UART", color: "#3b82f6" },
{ id: "SPI", name: "SPI", color: "#f43f5e" },
{ id: "USB", name: "USB", color: "#a855f7" },
{ id: "Clock", name: "Clock", color: "#eab308" },
{ id: "JTAG", name: "JTAG", color: "#6366f1" },
{ id: "Strapping", name: "Boot mode", color: "#dc2626" },
{ id: "DSI", name: "Display (DSI)", color: "#f97316" },
{ id: "CSI", name: "Camera (CSI)", color: "#14b8a6" },
{ id: "Ethernet", name: "Ethernet", color: "#0284c7" },
{ id: "SD", name: "SD Card", color: "#10b981" },
{ id: "I2C", name: "I2C", color: "#f59e0b" },
{ id: "Antena", name: "Antenna", color: "#06b6d4" },
];
const FILTER_CATEGORIES_ES = [
{ id: "All", name: "Todos", color: "#8b5cf6" },
{ id: "GND", name: "Tierra (GND)", color: "#64748b" },
{ id: "Power", name: "Alimentación", color: "#ef4444" },
{ id: "GPIO", name: "GPIO", color: "#22c55e" },
{ id: "Low Power", name: "GPIO LP", color: "#f59e0b" },
{ id: "ADC", name: "ADC", color: "#ec4899" },
{ id: "DAC", name: "DAC", color: "#a855f7" },
{ id: "Touch", name: "Touch", color: "#06b6d4" },
{ id: "UART", name: "UART", color: "#3b82f6" },
{ id: "SPI", name: "SPI", color: "#f43f5e" },
{ id: "USB", name: "USB", color: "#a855f7" },
{ id: "Clock", name: "Reloj", color: "#eab308" },
{ id: "JTAG", name: "JTAG", color: "#6366f1" },
{ id: "Strapping", name: "Arranque (Boot)", color: "#dc2626" },
{ id: "DSI", name: "Pantalla (DSI)", color: "#f97316" },
{ id: "CSI", name: "Cámara (CSI)", color: "#14b8a6" },
{ id: "Ethernet", name: "Ethernet", color: "#0284c7" },
{ id: "SD", name: "Tarjeta SD", color: "#10b981" },
{ id: "I2C", name: "I2C", color: "#f59e0b" },
{ id: "Antena", name: "Antena", color: "#06b6d4" },
];
const FILTER_CATEGORIES_FR = [
{ id: "All", name: "Tous", color: "#8b5cf6" },
{ id: "GND", name: "Masse (GND)", color: "#64748b" },
{ id: "Power", name: "Alimentation", color: "#ef4444" },
{ id: "GPIO", name: "GPIO", color: "#22c55e" },
{ id: "Low Power", name: "GPIO LP", color: "#f59e0b" },
{ id: "ADC", name: "ADC", color: "#ec4899" },
{ id: "DAC", name: "DAC", color: "#a855f7" },
{ id: "Touch", name: "Touch", color: "#06b6d4" },
{ id: "UART", name: "UART", color: "#3b82f6" },
{ id: "SPI", name: "SPI", color: "#f43f5e" },
{ id: "USB", name: "USB", color: "#a855f7" },
{ id: "Clock", name: "Horloge", color: "#eab308" },
{ id: "JTAG", name: "JTAG", color: "#6366f1" },
{ id: "Strapping", name: "Démarrage (Boot)", color: "#dc2626" },
{ id: "DSI", name: "Affichage (DSI)", color: "#f97316" },
{ id: "CSI", name: "Caméra (CSI)", color: "#14b8a6" },
{ id: "Ethernet", name: "Ethernet", color: "#0284c7" },
{ id: "SD", name: "Carte SD", color: "#10b981" },
{ id: "I2C", name: "I2C", color: "#f59e0b" },
{ id: "Antenne", name: "Antenne", color: "#06b6d4" },
];
const FILTER_CATEGORIES_DE = [
{ id: "All", name: "Alle", color: "#8b5cf6" },
{ id: "GND", name: "Masse (GND)", color: "#64748b" },
{ id: "Power", name: "Stromversorgung", color: "#ef4444" },
{ id: "GPIO", name: "GPIO", color: "#22c55e" },
{ id: "Low Power", name: "LP GPIO", color: "#f59e0b" },
{ id: "ADC", name: "ADC", color: "#ec4899" },
{ id: "DAC", name: "DAC", color: "#a855f7" },
{ id: "Touch", name: "Touch", color: "#06b6d4" },
{ id: "UART", name: "UART", color: "#3b82f6" },
{ id: "SPI", name: "SPI", color: "#f43f5e" },
{ id: "USB", name: "USB", color: "#a855f7" },
{ id: "Clock", name: "Takt", color: "#eab308" },
{ id: "JTAG", name: "JTAG", color: "#6366f1" },
{ id: "Strapping", name: "Bootmodus", color: "#dc2626" },
{ id: "DSI", name: "Display (DSI)", color: "#f97316" },
{ id: "CSI", name: "Kamera (CSI)", color: "#14b8a6" },
{ id: "Ethernet", name: "Ethernet", color: "#0284c7" },
{ id: "SD", name: "SD-Karte", color: "#10b981" },
{ id: "I2C", name: "I2C", color: "#f59e0b" },
{ id: "Antenne", name: "Antenne", color: "#06b6d4" },
];
const FILTER_CATEGORIES_ZH = [
{ id: "All", name: "全部", color: "#8b5cf6" },
{ id: "GND", name: "接地(GND)", color: "#64748b" },
{ id: "Power", name: "电源", color: "#ef4444" },
{ id: "GPIO", name: "GPIO", color: "#22c55e" },
{ id: "Low Power", name: "低功耗 GPIO", color: "#f59e0b" },
{ id: "ADC", name: "ADC", color: "#ec4899" },
{ id: "DAC", name: "DAC", color: "#a855f7" },
{ id: "Touch", name: "触摸", color: "#06b6d4" },
{ id: "UART", name: "UART", color: "#3b82f6" },
{ id: "SPI", name: "SPI", color: "#f43f5e" },
{ id: "USB", name: "USB", color: "#a855f7" },
{ id: "Clock", name: "时钟", color: "#eab308" },
{ id: "JTAG", name: "JTAG", color: "#6366f1" },
{ id: "Strapping", name: "启动配置", color: "#dc2626" },
{ id: "DSI", name: "显示(DSI)", color: "#f97316" },
{ id: "CSI", name: "摄像头(CSI)", color: "#14b8a6" },
{ id: "Ethernet", name: "以太网", color: "#0284c7" },
{ id: "SD", name: "SD 卡", color: "#10b981" },
{ id: "I2C", name: "I2C", color: "#f59e0b" },
{ id: "Antena", name: "天线", color: "#06b6d4" },
];
const type_colors = {
power: "#ef4444", // high-voltage red
ground: "#64748b", // slate gray
@@ -41,7 +156,30 @@ const type_colors = {
nc: "#94a3b8", // muted gray
};
export default function ConnectionsDiagram({ connections, serie }) {
/**
* Aceita ?pinos=28,30,31&motivo=... (gerado pela busca do site): mostra só
* esses pinos, pelo número físico, com um aviso para voltar à lista completa.
* O Suspense é exigido por useSearchParams em páginas estáticas.
*/
export default function ConnectionsDiagram(props) {
return (
<Suspense fallback={null}>
<ConnectionsDiagramInner {...props} />
</Suspense>
);
}
function ConnectionsDiagramInner({ connections, serie }) {
const params = useSearchParams();
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const router = useRouter();
const pinosFiltro = useMemo(() => new Set((params.get("pinos") ?? "").split(",").filter(Boolean)), [params]);
const motivoFiltro = params.get("motivo") ?? "";
const [activeFilter, setActiveFilter] = useState("All");
const [selectedConnection, setSelectedConnection] = useState(null);
const [searchQuery, setSearchQuery] = useState("");
@@ -50,6 +188,16 @@ export default function ConnectionsDiagram({ connections, serie }) {
const dialogRef = useRef(null);
const gatilhoRef = useRef(null);
const filterCategories = isEn
? FILTER_CATEGORIES_EN
: isEs
? FILTER_CATEGORIES_ES
: isFr
? FILTER_CATEGORIES_FR
: isZh ? FILTER_CATEGORIES_ZH : isDe
? FILTER_CATEGORIES_DE
: FILTER_CATEGORIES;
useEffect(() => {
setMounted(true);
}, []);
@@ -60,17 +208,45 @@ export default function ConnectionsDiagram({ connections, serie }) {
searchQuery === "" ||
connection.nome.toLowerCase().includes(searchQuery.toLowerCase()) ||
connection.numero.toString().toLowerCase().includes(searchQuery.toLowerCase());
return matchesFilter && matchesSearch;
const matchesPinos = pinosFiltro.size === 0 || pinosFiltro.has(String(connection.numero));
return matchesFilter && matchesSearch && matchesPinos;
};
const getCategoryColor = (category) => {
const filter = FILTER_CATEGORIES.find((f) => f.id === category);
const filter = filterCategories.find((f) => f.id === category);
return filter?.color || "#64748b";
};
const nomeCategoria = (cat) => (cat === "Strapping" ? "Inicialização" : cat);
const nomeCategoria = (cat) => {
if (cat === "Strapping") {
return isEn ? "Boot mode" : isEs ? "Arranque (Boot)" : isFr ? "Démarrage (Boot)" : isZh ? "启动配置" : isDe ? "Bootmodus" : "Inicialização";
}
if (isEn) {
const found = FILTER_CATEGORIES_EN.find((f) => f.id === cat);
if (found) return found.name;
}
if (isEs) {
const found = FILTER_CATEGORIES_ES.find((f) => f.id === cat);
if (found) return found.name;
}
if (isFr) {
const found = FILTER_CATEGORIES_FR.find((f) => f.id === cat);
if (found) return found.name;
}
if (isDe) {
const found = FILTER_CATEGORIES_DE.find((f) => f.id === cat);
if (found) return found.name;
}
if (isZh) {
const found = FILTER_CATEGORIES_ZH.find((f) => f.id === cat);
if (found) return found.name;
}
return cat;
};
const visibleConnections = useMemo(() => connections.filter(isConnectionVisible), [connections, activeFilter, searchQuery]);
const visibleConnections = useMemo(() => connections.filter(isConnectionVisible), [connections, activeFilter, searchQuery, pinosFiltro]);
const mostrarTodos = () => router.replace(`${pathname}#connections`, { scroll: false });
const abrir = (connection, evento) => {
gatilhoRef.current = evento.currentTarget;
@@ -120,8 +296,20 @@ export default function ConnectionsDiagram({ connections, serie }) {
return (
<div className="px-4 py-14 text-center">
<Sliders className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
<p className="mt-4 font-display text-xl font-semibold text-ink">Diagrama de conexões indisponível</p>
<p className="mt-1 text-sm text-muted">Este modelo ainda não tem um mapa detalhado de conexões e barramentos.</p>
<p className="mt-4 font-display text-xl font-semibold text-ink">
{isEn ? "Pinout diagram unavailable" : isEs ? "Diagrama de conexiones no disponible" : isFr ? "Brochage non disponible" : isZh ? "连接图暂不可用" : isDe ? "Pinbelegungsdiagramm nicht verfügbar" : "Diagrama de conexões indisponível"}
</p>
<p className="mt-1 text-sm text-muted">
{isEn
? "This model does not yet have a detailed pinout and bus map."
: isEs
? "Este modelo todavía no dispone de un mapa detallado de conexiones y buses."
: isFr
? "Ce modèle ne dispose pas encore d'un plan détaillé des broches et des bus."
: isZh ? "该型号尚无详细的连接与总线图。" : isDe
? "Dieses Modell verfügt noch über keinen detaillierten Pinbelegungs- und Busplan."
: "Este modelo ainda não tem um mapa detalhado de conexões e barramentos."}
</p>
</div>
);
}
@@ -131,47 +319,98 @@ export default function ConnectionsDiagram({ connections, serie }) {
return (
<div className="space-y-6">
<div>
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">Diagrama de conexões interativo</h2>
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">
{isEn ? "Interactive pinout diagram" : isEs ? "Diagrama de conexiones interactivo" : isFr ? "Brochage interactif" : isZh ? "交互式连接图" : isDe ? "Interaktives Pinbelegungsdiagramm" : "Diagrama de conexões interativo"}
</h2>
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-muted">
Todas as conexões e a multiplexação do {serie.nome_completo}. Busque por nome ou número, filtre por função e abra um pino para ver os detalhes.
{isEn ? (
`All connections and multiplexing for the ${serie.nome_completo}. Search by name or number, filter by function, and open a pin to see details.`
) : isEs ? (
`Todas las conexiones y la multiplexación del ${serie.nome_completo}. Busque por nombre o número, filtre por función y abra un pin para ver los detalles.`
) : isFr ? (
`Toutes les connexions et le multiplexage de l'${serie.nome_completo}. Recherchez par nom ou numéro, filtrez par fonction et ouvrez une broche pour voir les détails.`
) : isZh ? ( `${serie.nome_completo} 的全部连接与复用。可按名称或编号搜索、按功能筛选,并展开引脚查看详情。` ) : isDe ? (
`Alle Anschlüsse und das Multiplexing des ${serie.nome_completo}. Suchen Sie nach Name oder Nummer, filtern Sie nach Funktion und öffnen Sie einen Pin für Details.`
) : (
`Todas as conexões e a multiplexação do ${serie.nome_completo}. Busque por nome ou número, filtre por função e abra um pino para ver os detalhes.`
)}
</p>
</div>
{pinosFiltro.size > 0 && (
<div role="status" className="callout flex flex-wrap items-center justify-between gap-3">
<p className="text-sm text-ink">
<strong className="font-semibold">
{isEn ? "Filtered by search:" : isEs ? "Filtrado por la búsqueda:" : isFr ? "Filtré par la recherche :" : isZh ? "按搜索筛选:" : isDe ? "Nach Suche gefiltert:" : "Filtrado pela busca:"}
</strong>{" "}
{motivoFiltro || (isEn ? "selected pins" : isEs ? "pines seleccionados" : isFr ? "broches sélectionnées" : isZh ? "个引脚已选中" : isDe ? "ausgewählte Pins" : "pinos selecionados")} ({pinosFiltro.size}{" "}
{pinosFiltro.size === 1
? (isEn ? "pin" : isEs ? "pin" : isFr ? "broche" : isZh ? "个引脚" : isDe ? "Pin" : "pino")
: (isEn ? "pins" : isEs ? "pines" : isFr ? "broches" : isZh ? "个引脚" : isDe ? "Pins" : "pinos")})
</p>
<button type="button" onClick={mostrarTodos} className="btn btn-ghost btn-sm">
{isEn ? "Show all pins" : isEs ? "Mostrar todos los pines" : isFr ? "Afficher toutes les broches" : isZh ? "显示全部引脚" : isDe ? "Alle Pins anzeigen" : "Mostrar todos os pinos"}
</button>
</div>
)}
<div className="flex flex-col gap-3 sm:flex-row">
<div className="relative flex-1">
<label htmlFor="busca-pino" className="sr-only">Buscar conexão por nome ou número</label>
<label htmlFor="busca-pino" className="sr-only">
{isEn ? "Search connection by name or number" : isEs ? "Buscar conexión por nombre o número" : isFr ? "Rechercher une connexion par nom ou numéro" : isZh ? "按名称或编号搜索连接" : isDe ? "Anschluss nach Name oder Nummer suchen" : "Buscar conexão por nome ou número"}
</label>
<Search className="pointer-events-none absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted" aria-hidden="true" />
<input
id="busca-pino"
type="search"
placeholder="Buscar pino (ex.: GPIO1, TXD, XTAL)"
placeholder={
isEn
? "Search pin (e.g.: GPIO1, TXD, XTAL)"
: isEs
? "Buscar pin (ej.: GPIO1, TXD, XTAL)"
: isFr
? "Rechercher une broche (ex. : GPIO1, TXD, XTAL)"
: isZh ? "搜索引脚(例如:GPIO1、TXD、XTAL)" : isDe
? "Pin suchen (z. B.: GPIO1, TXD, XTAL)"
: "Buscar pino (ex.: GPIO1, TXD, XTAL)"
}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
autoComplete="off"
className="field pl-11 pr-4 text-sm"
/>
</div>
<div role="group" aria-label="Modo de exibição" className="flex gap-2">
<div role="group" aria-label={isEn ? "Display mode" : isEs ? "Modo de visualización" : isFr ? "Mode d'affichage" : isZh ? "显示模式" : isDe ? "Anzeigemodus" : "Modo de exibição"} className="flex gap-2">
<button type="button" onClick={() => setViewMode("grid")} aria-pressed={viewMode === "grid"} className="chip-btn">
<Grid className="h-4 w-4" aria-hidden="true" />
Grade
{isEn ? "Grid" : isEs ? "Cuadrícula" : isFr ? "Grille" : isZh ? "网格" : isDe ? "Raster" : "Grade"}
</button>
<button type="button" onClick={() => setViewMode("list")} aria-pressed={viewMode === "list"} className="chip-btn">
<List className="h-4 w-4" aria-hidden="true" />
Lista
{isEn ? "List" : isEs ? "Lista" : isFr ? "Liste" : isZh ? "列表" : isDe ? "Liste" : "Lista"}
</button>
</div>
</div>
<div>
<div className="flex items-center justify-between gap-3">
<h3 className="text-sm font-semibold text-ink">Função do pino</h3>
<h3 className="text-sm font-semibold text-ink">{isEn ? "Pin function" : isEs ? "Función del pin" : isFr ? "Fonction de la broche" : isZh ? "引脚功能" : isDe ? "Pin-Funktion" : "Função do pino"}</h3>
<p role="status" aria-live="polite" className="text-sm text-muted">
{visibleConnections.length} de {connections.length} pinos
{isEn ? (
`${visibleConnections.length} of ${connections.length} pins`
) : isEs ? (
`${visibleConnections.length} de ${connections.length} pines`
) : isFr ? (
`${visibleConnections.length} sur ${connections.length} broches`
) : isZh ? ( `共 ${connections.length} 个引脚,显示 ${visibleConnections.length} 个` ) : isDe ? (
`${visibleConnections.length} von ${connections.length} Pins`
) : (
`${visibleConnections.length} de ${connections.length} pinos`
)}
</p>
</div>
<div role="group" aria-label="Filtrar por função" className="mt-3 flex flex-wrap gap-2">
{FILTER_CATEGORIES.map((filter) => {
<div role="group" aria-label={isEn ? "Filter by function" : isEs ? "Filtrar por función" : isFr ? "Filtrer par fonction" : isZh ? "按功能筛选" : isDe ? "Nach Funktion filtern" : "Filtrar por função"} className="mt-3 flex flex-wrap gap-2">
{filterCategories.map((filter) => {
const isActive = activeFilter === filter.id;
const count = connections.filter((c) => (filter.id === "All" ? true : c.categorias.includes(filter.id))).length;
if (count === 0 && !isActive) return null; // filtros que não se aplicam a este chip
@@ -189,10 +428,20 @@ export default function ConnectionsDiagram({ connections, serie }) {
{visibleConnections.length === 0 ? (
<div className="rounded-2xl border border-dashed border-line-strong px-6 py-12 text-center">
<Search className="mx-auto h-8 w-8 text-muted" aria-hidden="true" />
<p className="mt-3 font-semibold text-ink">Nenhuma conexão encontrada</p>
<p className="mt-1 text-sm text-muted">Ajuste a busca ou volte para todas as funções.</p>
<button type="button" onClick={() => { setActiveFilter("All"); setSearchQuery(""); }} className="btn btn-primary btn-sm mt-5">
Limpar busca e filtros
<p className="mt-3 font-semibold text-ink">{isEn ? "No connections found" : isEs ? "No se encontraron conexiones" : isFr ? "Aucune connexion trouvée" : isZh ? "未找到连接" : isDe ? "Keine Anschlüsse gefunden" : "Nenhuma conexão encontrada"}</p>
<p className="mt-1 text-sm text-muted">
{isEn
? "Adjust your search or return to all functions."
: isEs
? "Ajuste la búsqueda o vuelva a todas las funciones."
: isFr
? "Ajustez votre recherche ou revenez à toutes les fonctions."
: isZh ? "请调整搜索,或返回全部功能。" : isDe
? "Passen Sie Ihre Suche an oder kehren Sie zu allen Funktionen zurück."
: "Ajuste a busca ou volte para todas as funções."}
</p>
<button type="button" onClick={() => { setActiveFilter("All"); setSearchQuery(""); if (pinosFiltro.size) mostrarTodos(); }} className="btn btn-primary btn-sm mt-5">
{isEn ? "Clear search and filters" : isEs ? "Limpiar búsqueda y filtros" : isFr ? "Effacer la recherche et les filtres" : isZh ? "清除搜索和筛选" : isDe ? "Suche und Filter zurücksetzen" : "Limpar busca e filtros"}
</button>
</div>
) : viewMode === "grid" ? (
@@ -205,7 +454,17 @@ export default function ConnectionsDiagram({ connections, serie }) {
type="button"
onClick={(e) => abrir(connection, e)}
aria-haspopup="dialog"
aria-label={`Pino ${connection.nome}, número ${connection.numero}${connection.avisos ? ", com restrições de uso" : ""}`}
aria-label={
isEn
? `Pin ${connection.nome}, number ${connection.numero}${connection.avisos ? ", with usage restrictions" : ""}`
: isEs
? `Pin ${connection.nome}, número ${connection.numero}${connection.avisos ? ", con restricciones de uso" : ""}`
: isFr
? `Broche ${connection.nome}, numéro ${connection.numero}${connection.avisos ? ", avec restrictions d'utilisation" : ""}`
: isZh ? `引脚 ${connection.nome},编号 ${connection.numero}${connection.avisos ? ",有使用限制" : ""}` : isDe
? `Pin ${connection.nome}, Nummer ${connection.numero}${connection.avisos ? ", mit Nutzungseinschränkungen" : ""}`
: `Pino ${connection.nome}, número ${connection.numero}${connection.avisos ? ", com restrições de uso" : ""}`
}
className="flex w-full flex-col items-center rounded-xl border border-line bg-surface p-3 transition-colors hover:bg-surface-2"
>
<span
@@ -233,13 +492,23 @@ export default function ConnectionsDiagram({ connections, serie }) {
) : (
<div className="overflow-x-auto rounded-xl border border-line">
<table className="w-full min-w-[40rem] border-collapse text-left text-sm">
<caption className="sr-only">Conexões do {serie.nome_completo}</caption>
<caption className="sr-only">
{isEn
? `Connections of ${serie.nome_completo}`
: isEs
? `Conexiones del ${serie.nome_completo}`
: isFr
? `Connexions de l'${serie.nome_completo}`
: isZh ? `${serie.nome_completo} 的连接` : isDe
? `Anschlüsse des ${serie.nome_completo}`
: `Conexões do ${serie.nome_completo}`}
</caption>
<thead>
<tr className="border-b border-line bg-surface-2 text-muted">
<th scope="col" className="px-4 py-3 font-medium">Pino</th>
<th scope="col" className="px-4 py-3 font-medium">Nome</th>
<th scope="col" className="px-4 py-3 font-medium">Funções</th>
<th scope="col" className="px-4 py-3 font-medium">Uso</th>
<th scope="col" className="px-4 py-3 font-medium">{isEn ? "Pin" : isEs ? "Pin" : isFr ? "Broche" : isZh ? "引脚" : isDe ? "Pin" : "Pino"}</th>
<th scope="col" className="px-4 py-3 font-medium">{isEn ? "Name" : isEs ? "Nombre" : isFr ? "Nom" : isZh ? "名称" : isDe ? "Name" : "Nome"}</th>
<th scope="col" className="px-4 py-3 font-medium">{isEn ? "Functions" : isEs ? "Funciones" : isFr ? "Fonctions" : isZh ? "功能" : isDe ? "Funktionen" : "Funções"}</th>
<th scope="col" className="px-4 py-3 font-medium">{isEn ? "Usage" : isEs ? "Uso" : isFr ? "Utilisation" : isZh ? "用途" : isDe ? "Nutzung" : "Uso"}</th>
</tr>
</thead>
<tbody className="divide-y divide-line">
@@ -252,7 +521,17 @@ export default function ConnectionsDiagram({ connections, serie }) {
type="button"
onClick={(e) => abrir(connection, e)}
aria-haspopup="dialog"
aria-label={`Abrir detalhes do pino ${connection.nome}, número ${connection.numero}`}
aria-label={
isEn
? `Open pin details for ${connection.nome}, number ${connection.numero}`
: isEs
? `Abrir detalles del pin ${connection.nome}, número ${connection.numero}`
: isFr
? `Ouvrir les détails de la broche ${connection.nome}, numéro ${connection.numero}`
: isZh ? `展开引脚 ${connection.nome} 的详情,编号 ${connection.numero}` : isDe
? `Pindetails für ${connection.nome}, Nummer ${connection.numero} öffnen`
: `Abrir detalhes do pino ${connection.nome}, número ${connection.numero}`
}
className="grid h-11 w-11 place-items-center rounded-full border-2 bg-surface text-sm font-semibold tabular-nums text-ink hover:bg-surface-2"
style={{ borderColor: baseColor }}
>
@@ -267,12 +546,12 @@ export default function ConnectionsDiagram({ connections, serie }) {
{connection.avisos ? (
<span className="inline-flex items-center gap-1.5 font-medium text-danger">
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
Restrito
{isEn ? "Restricted" : isEs ? "Restringido" : isFr ? "Restreint" : isZh ? "受限" : isDe ? "Eingeschränkt" : "Restrito"}
</span>
) : (
<span className="inline-flex items-center gap-1.5 text-ok">
<CheckCircle className="h-4 w-4" aria-hidden="true" />
Livre
{isEn ? "Free" : isEs ? "Libre" : isFr ? "Libre" : isZh ? "可用" : isDe ? "Frei" : "Livre"}
</span>
)}
</td>
@@ -288,10 +567,37 @@ export default function ConnectionsDiagram({ connections, serie }) {
<div className="callout callout-warn flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
<div>
<p className="font-semibold text-ink">Notas sobre a pinagem</p>
<p className="font-semibold text-ink">{isEn ? "Pinout notes" : isEs ? "Notas sobre el patillaje" : isFr ? "Remarques sur le brochage" : isZh ? "引脚说明" : isDe ? "Hinweise zur Pinbelegung" : "Notas sobre a pinagem"}</p>
<ul className="mt-1 list-disc space-y-1 pl-5">
<li>Pinos com o ícone de alerta têm papel especial no boot ou limitações analógicas. Abra o pino para ver os detalhes.</li>
<li>Isole os circuitos de toque capacitivo de pinos com ruído de RF acoplado.</li>
{isEn ? (
<>
<li>Pins with a warning icon have special boot roles or analog limitations. Open the pin to see details.</li>
<li>Isolate capacitive touch traces from coupled RF noise.</li>
</>
) : isEs ? (
<>
<li>Los pines con icono de advertencia tienen un papel especial en el arranque o limitaciones analógicas. Abra el pin para ver los detalles.</li>
<li>Aísle las pistas táctiles capacitivas del ruido de RF acoplado.</li>
</>
) : isFr ? (
<>
<li>Les broches signalées par une icône d'avertissement ont un rôle spécial au démarrage ou des restrictions analogiques. Ouvrez la broche pour voir les détails.</li>
<li>Isolez les pistes tactiles capacitives des bruits RF couplés.</li>
</>
) : isZh ? ( <>
<li>带警告图标的引脚在启动时有特殊作用,或存在模拟功能限制。展开该引脚查看详情。</li>
<li>请将电容触摸电路与耦合了射频噪声的引脚隔离开。</li>
</> ) : isDe ? (
<>
<li>Pins mit einem Warnsymbol spielen eine besondere Rolle beim Booten oder unterliegen analogen Einschränkungen. Öffnen Sie den Pin für Details.</li>
<li>Isolieren Sie kapazitive Touch-Leitungen von eingekoppeltem HF-Rauschen.</li>
</>
) : (
<>
<li>Pinos com o ícone de alerta têm papel especial no boot ou limitações analógicas. Abra o pino para ver os detalhes.</li>
<li>Isole os circuitos de toque capacitivo de pinos com ruído de RF acoplado.</li>
</>
)}
</ul>
</div>
</div>
@@ -319,10 +625,25 @@ export default function ConnectionsDiagram({ connections, serie }) {
<h3 id="modal-title" className="break-words font-display text-2xl font-semibold tracking-[-0.03em] text-ink">
{selectedConnection.nome}
</h3>
<p className="text-sm text-muted">Pino físico {selectedConnection.numero}</p>
<p className="text-sm text-muted">
{isEn
? `Physical pin ${selectedConnection.numero}`
: isEs
? `Pin físico ${selectedConnection.numero}`
: isFr
? `Broche physique ${selectedConnection.numero}`
: isZh ? `物理引脚 ${selectedConnection.numero}` : isDe
? `Physischer Pin ${selectedConnection.numero}`
: `Pino físico ${selectedConnection.numero}`}
</p>
</div>
</div>
<button type="button" onClick={fechar} aria-label="Fechar detalhes do pino" className="grid h-11 w-11 shrink-0 place-items-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-ink">
<button
type="button"
onClick={fechar}
aria-label={isEn ? "Close pin details" : isEs ? "Cerrar detalles del pin" : isFr ? "Fermer les détails de la broche" : isZh ? "关闭引脚详情" : isDe ? "Pindetails schließen" : "Fechar detalhes do pino"}
className="grid h-11 w-11 shrink-0 place-items-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-ink"
>
<X className="h-5 w-5" aria-hidden="true" />
</button>
</div>
@@ -330,7 +651,7 @@ export default function ConnectionsDiagram({ connections, serie }) {
<div className="flex-1 space-y-6 overflow-y-auto p-5 sm:p-7">
{selectedConnection.categorias.length > 0 && (
<section>
<h4 className="text-sm font-semibold text-ink">Categorias</h4>
<h4 className="text-sm font-semibold text-ink">{isEn ? "Categories" : isEs ? "Categorías" : isFr ? "Catégories" : isZh ? "类别" : isDe ? "Kategorien" : "Categorias"}</h4>
<ul className="mt-3 flex flex-wrap gap-2">
{selectedConnection.categorias.map((cat) => (
<li key={cat} className="chip">
@@ -346,7 +667,7 @@ export default function ConnectionsDiagram({ connections, serie }) {
<section>
<h4 className="flex items-center gap-2 text-sm font-semibold text-ink">
<Zap className="h-4 w-4 text-danger" aria-hidden="true" />
Domínio de alimentação
{isEn ? "Power domain" : isEs ? "Dominio de alimentación" : isFr ? "Domaine d'alimentation" : isZh ? "供电域" : isDe ? "Spannungsbereich" : "Domínio de alimentação"}
</h4>
<ul className="tile mt-3 space-y-2">
{selectedConnection.alimentacao.map((source) => (
@@ -357,7 +678,7 @@ export default function ConnectionsDiagram({ connections, serie }) {
)}
<section>
<h4 className="text-sm font-semibold text-ink">Funções disponíveis</h4>
<h4 className="text-sm font-semibold text-ink">{isEn ? "Available functions" : isEs ? "Funciones disponibles" : isFr ? "Fonctions disponibles" : isZh ? "可用功能" : isDe ? "Verfügbare Funktionen" : "Funções disponíveis"}</h4>
<ul className="tile mt-3 grid gap-2.5 sm:grid-cols-2">
{selectedConnection.funcoes.map((func) => (
<li key={func} className="flex items-center gap-2.5 text-sm text-ink-soft">
@@ -372,7 +693,7 @@ export default function ConnectionsDiagram({ connections, serie }) {
<section className="callout callout-danger">
<h4 className="flex items-center gap-2 font-semibold text-ink">
<AlertTriangle className="h-4 w-4 text-danger" aria-hidden="true" />
Avisos de engenharia
{isEn ? "Engineering notes" : isEs ? "Notas de ingeniería" : isFr ? "Notes d'ingénierie" : isZh ? "工程警告" : isDe ? "Entwicklungshinweise" : "Avisos de engenharia"}
</h4>
<ul className="mt-2 list-disc space-y-1.5 pl-5">
{selectedConnection.avisos.map((aviso) => (
@@ -384,7 +705,9 @@ export default function ConnectionsDiagram({ connections, serie }) {
</div>
<div className="border-t border-line p-4 sm:px-7">
<button type="button" onClick={fechar} className="btn btn-primary w-full">Fechar</button>
<button type="button" onClick={fechar} className="btn btn-primary w-full">
{isEn ? "Close" : isEs ? "Cerrar" : isFr ? "Fermer" : isZh ? "关闭" : isDe ? "Schließen" : "Fechar"}
</button>
</div>
</div>
</div>,
+313 -45
View File
@@ -1,9 +1,14 @@
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import Logo from "@/components/Logo";
import GiteaMark from "@/components/GiteaMark";
import { ArrowUpRight } from "lucide-react";
import { SITE } from "@/lib/seo";
import { LOCALES, getLocalizedHref } from "@/i18n/links";
const COLUMNS = [
const COLUMNS_PT = [
{
title: "Explorar",
links: [
@@ -33,58 +38,282 @@ const COLUMNS = [
},
];
const COLUMNS_EN = [
{
title: "Explore",
links: [
{ href: "/series", label: "ESP32 Series" },
{ href: "/comparacao", label: "Comparator" },
{ href: "/catalogo", label: "Board Catalog" },
],
},
{
title: "Tools",
links: [
{ href: "/seletor", label: "Smart Selector" },
{ href: "/diagnostico", label: "Diagnostics" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "Frameworks & SDKs" },
],
},
{
title: "Project",
links: [
{ href: "/sobre", label: "About ESPDocs" },
{ href: "/glossario", label: "Glossary" },
{ href: SITE.repositorio, label: "Repository", external: true },
{ href: `${SITE.repositorio}/issues`, label: "Report an issue", external: true },
],
},
];
const COLUMNS_ES = [
{
title: "Explorar",
links: [
{ href: "/series", label: "Series ESP32" },
{ href: "/comparacao", label: "Comparador" },
{ href: "/catalogo", label: "Catálogo de placas" },
],
},
{
title: "Herramientas",
links: [
{ href: "/seletor", label: "Selector inteligente" },
{ href: "/diagnostico", label: "Diagnóstico" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "Frameworks y SDKs" },
],
},
{
title: "Proyecto",
links: [
{ href: "/sobre", label: "Acerca de ESPDocs" },
{ href: "/glossario", label: "Glosario" },
{ href: SITE.repositorio, label: "Repositorio", external: true },
{ href: `${SITE.repositorio}/issues`, label: "Reportar un problema", external: true },
],
},
];
const COLUMNS_FR = [
{
title: "Explorer",
links: [
{ href: "/series", label: "Séries ESP32" },
{ href: "/comparacao", label: "Comparateur" },
{ href: "/catalogo", label: "Catalogue de cartes" },
],
},
{
title: "Outils",
links: [
{ href: "/seletor", label: "Sélecteur intelligent" },
{ href: "/diagnostico", label: "Diagnostic" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "Frameworks et SDKs" },
],
},
{
title: "Projet",
links: [
{ href: "/sobre", label: "À propos d'ESPDocs" },
{ href: "/glossario", label: "Glossaire" },
{ href: SITE.repositorio, label: "Dépôt", external: true },
{ href: `${SITE.repositorio}/issues`, label: "Signaler un problème", external: true },
],
},
];
const COLUMNS_DE = [
{
title: "Erkunden",
links: [
{ href: "/series", label: "ESP32-Serien" },
{ href: "/comparacao", label: "Vergleich" },
{ href: "/catalogo", label: "Board-Katalog" },
],
},
{
title: "Werkzeuge",
links: [
{ href: "/seletor", label: "Intelligente Auswahl" },
{ href: "/diagnostico", label: "Diagnose" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "Frameworks & SDKs" },
],
},
{
title: "Projekt",
links: [
{ href: "/sobre", label: "Über ESPDocs" },
{ href: "/glossario", label: "Glossar" },
{ href: SITE.repositorio, label: "Repository", external: true },
{ href: `${SITE.repositorio}/issues`, label: "Problem melden", external: true },
],
},
];
const COLUMNS_ZH = [
{
title: "探索",
links: [
{ href: "/series", label: "ESP32 系列" },
{ href: "/comparacao", label: "对比工具" },
{ href: "/catalogo", label: "开发板目录" },
],
},
{
title: "工具",
links: [
{ href: "/seletor", label: "智能选型" },
{ href: "/diagnostico", label: "故障诊断" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "框架与 SDK" },
],
},
{
title: "项目",
links: [
{ href: "/sobre", label: "关于 ESPDocs" },
{ href: "/glossario", label: "术语表" },
{ href: SITE.repositorio, label: "代码仓库", external: true },
{ href: `${SITE.repositorio}/issues`, label: "反馈问题", external: true },
],
},
];
export default function Footer() {
const pathname = usePathname() || "";
const year = new Date().getFullYear();
const currentLocale =
LOCALES.find((l) => pathname === `/${l.code}` || pathname.startsWith(`/${l.code}/`))?.code || "pt";
const isPt = currentLocale === "pt";
const isEn = currentLocale === "en";
const isEs = currentLocale === "es";
const isFr = currentLocale === "fr";
const isDe = currentLocale === "de";
const isZh = currentLocale === "zh-CN";
const getLinkHref = (href) => getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
const columns = isPt
? COLUMNS_PT.map((column) => ({
...column,
links: column.links.filter((link) => link.href !== "/livro" || isPt),
}))
: isEs
? COLUMNS_ES
: isFr
? COLUMNS_FR
: isZh ? COLUMNS_ZH : isDe
? COLUMNS_DE
: COLUMNS_EN;
return (
<footer className="mt-20 border-t border-line md:mt-28" aria-label="Rodapé do ESPDocs">
<footer
className="mt-20 border-t border-line md:mt-28"
aria-label={
isPt
? "Rodapé do ESPDocs"
: isEs
? "Pie de página de ESPDocs"
: isFr
? "Pied de page d'ESPDocs"
: isZh ? "ESPDocs 页脚" : isDe
? "ESPDocs-Fußzeile"
: "ESPDocs footer"
}
>
<div className="shell py-14 md:py-20">
<div className="grid gap-12 lg:grid-cols-[1.1fr_2fr]">
<div>
<Link href="/" className="inline-flex min-h-11 items-center gap-2.5" aria-label="ESPDocs, página inicial">
<Link
href={getLinkHref("/")}
className="inline-flex min-h-11 items-center gap-2.5"
aria-label={
isPt
? "ESPDocs, página inicial"
: isEs
? "ESPDocs, página de inicio"
: isFr
? "ESPDocs, page d'accueil"
: isZh ? "ESPDocs,首页" : isDe
? "ESPDocs, Startseite"
: "ESPDocs, homepage"
}
>
<Logo className="h-7 w-7" />
<span className="font-display text-2xl font-semibold tracking-[-0.045em] text-ink">ESPDocs</span>
</Link>
<p className="mt-5 max-w-sm text-sm leading-relaxed text-muted">
Documentação independente do ecossistema ESP32, escrita em português brasileiro.
Dados públicos, curadoria editorial e links para as fontes oficiais.
{isPt ? (
<>
Documentação independente do ecossistema ESP32, escrita em português brasileiro.
Dados públicos, curadoria editorial e links para as fontes oficiais.
</>
) : isEs ? (
<>
Documentación independiente del ecosistema ESP32.
Datos públicos, curaduría editorial y enlaces a las fuentes oficiales.
</>
) : isFr ? (
<>
Documentation indépendante de l&apos;écosystème ESP32.
Données publiques, sélection éditoriale et liens vers les sources officielles.
</>
) : isZh ? ( <>ESP32 生态的独立文档。公开数据、编辑整理,并链接到官方资料来源。</> ) : isDe ? (
<>
Unabhängige Dokumentation des ESP32-Ökosystems.
Öffentliche Daten, redaktionelle Betreuung und Links zu offiziellen Quellen.
</>
) : (
<>
Independent documentation of the ESP32 ecosystem.
Open data, editorial curation, and links to official sources.
</>
)}
</p>
<Link
href="/livro"
className="group mt-7 grid grid-cols-[3rem_1fr_auto] items-center gap-3.5 rounded-2xl border border-line bg-surface p-3.5 transition-colors duration-300 hover:border-line-strong"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={SITE.livroCapa}
alt=""
aria-hidden="true"
width={48}
height={72}
className="h-[72px] w-12 rounded-md object-cover shadow-md"
/>
<span className="min-w-0">
<span className="text-xs font-semibold text-accent">Livro novo</span>
<span className="mt-0.5 block font-display text-base font-semibold leading-tight text-ink">Microcontroladores ESP32</span>
<span className="mt-1 block text-xs text-muted">Conectividade, eficiência e desempenho</span>
</span>
<ArrowUpRight className="h-4 w-4 text-faint transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-accent" aria-hidden="true" />
</Link>
{isPt && (
<>
<Link
href="/pt/livro"
className="group mt-7 grid grid-cols-[3rem_1fr_auto] items-center gap-3.5 rounded-2xl border border-line bg-surface p-3.5 transition-colors duration-300 hover:border-line-strong"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={SITE.livroCapa}
alt=""
aria-hidden="true"
width={48}
height={72}
className="h-[72px] w-12 rounded-md object-cover shadow-md"
/>
<span className="min-w-0">
<span className="text-xs font-semibold text-accent">Livro novo</span>
<span className="mt-0.5 block font-display text-base font-semibold leading-tight text-ink">Microcontroladores ESP32</span>
<span className="mt-1 block text-xs text-muted">Conectividade, eficiência e desempenho</span>
</span>
<ArrowUpRight className="h-4 w-4 text-faint transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-accent" aria-hidden="true" />
</Link>
<div className="mt-4 flex flex-wrap gap-x-5 gap-y-2 text-sm">
<a href={SITE.livroAmazon} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
Amazon
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
<a href={SITE.livroUiclap} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
UICLAP
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
</div>
<div className="mt-4 flex flex-wrap gap-x-5 gap-y-2 text-sm">
<a href={SITE.livroAmazon} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
Amazon
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
<a href={SITE.livroUiclap} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
UICLAP
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
</div>
</>
)}
</div>
<div className="grid grid-cols-2 gap-8 sm:grid-cols-4">
{COLUMNS.map((column) => (
{columns.map((column) => (
<nav key={column.title} aria-label={column.title}>
<h2 className="text-sm font-semibold text-ink">{column.title}</h2>
<ul className="mt-2 space-y-0">
@@ -101,7 +330,7 @@ export default function Footer() {
<ArrowUpRight className="h-3 w-3" aria-hidden="true" />
</a>
) : (
<Link href={link.href} className="inline-flex min-h-11 min-w-11 items-center text-sm text-muted transition-colors hover:text-accent">
<Link href={getLinkHref(link.href)} className="inline-flex min-h-11 min-w-11 items-center text-sm text-muted transition-colors hover:text-accent">
{link.label}
</Link>
)}
@@ -112,7 +341,7 @@ export default function Footer() {
))}
<div>
<h2 className="text-sm font-semibold text-ink">Autor</h2>
<h2 className="text-sm font-semibold text-ink">{isPt ? "Autor" : isEs ? "Autor" : isFr ? "Auteur" : isZh ? "作者" : isDe ? "Autor" : "Author"}</h2>
<p className="mt-4 text-sm leading-relaxed text-muted">
Lucas Rayan Guerra
<br />
@@ -123,18 +352,36 @@ export default function Footer() {
href={SITE.repositorio}
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub do projeto (abre em nova aba)"
aria-label={
isPt
? "Gitea do projeto (abre em nova aba)"
: isEs
? "Gitea del proyecto (abre en una pestaña nueva)"
: isFr
? "Gitea du projet (ouvre un nouvel onglet)"
: isZh ? "项目 Gitea(在新标签页打开)" : isDe
? "Projekt-Gitea (öffnet in neuem Tab)"
: "Project Gitea (opens in new tab)"
}
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:border-line-strong hover:bg-surface"
>
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12 .5a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2.1c-3.3.7-4-1.6-4-1.6-.5-1.2-1.2-1.5-1.2-1.5-1-.7.1-.7.1-.7 1.1.1 1.7 1.1 1.7 1.1 1 .1 1.6-.7 1.9-1 .1-.8.4-1.3.8-1.6-2.6-.3-5.3-1.3-5.3-5.8 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.6.1-3.3 0 0 1-.3 3.3 1.2a11.4 11.4 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 3 .1 3.3.8.8 1.2 1.9 1.2 3.1 0 4.5-2.7 5.5-5.3 5.8.5.4.9 1.1.9 2.2v3.2c0 .3.2.7.8.6A12 12 0 0 0 12 .5z" />
</svg>
<GiteaMark className="h-4 w-4" />
</a>
<a
href={SITE.autorLinkedin}
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn do autor (abre em nova aba)"
aria-label={
isPt
? "LinkedIn do autor (abre em nova aba)"
: isEs
? "LinkedIn del autor (abre en una pestaña nueva)"
: isFr
? "LinkedIn de l'auteur (ouvre un nouvel onglet)"
: isZh ? "作者 LinkedIn(在新标签页打开)" : isDe
? "LinkedIn des Autors (öffnet in neuem Tab)"
: "Author LinkedIn (opens in new tab)"
}
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:border-line-strong hover:bg-surface"
>
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -147,7 +394,18 @@ export default function Footer() {
</div>
<div className="mt-14 flex flex-col gap-4 border-t border-line pt-6 text-xs leading-relaxed text-faint md:flex-row md:items-center md:justify-between">
<p>© {year} ESPDocs. Projeto independente, sem afiliação com a Espressif Systems.</p>
<p>
© {year}{" "}
{isPt
? "ESPDocs. Projeto independente, sem afiliação com a Espressif Systems."
: isEs
? "ESPDocs. Proyecto independiente, sin afiliación con Espressif Systems."
: isFr
? "ESPDocs. Projet indépendant, sans affiliation avec Espressif Systems."
: isZh ? "ESPDocs。独立项目,与乐鑫(Espressif Systems)无任何关联。" : isDe
? "ESPDocs. Unabhängiges Projekt, nicht verbunden mit Espressif Systems."
: "ESPDocs. Independent project, not affiliated with Espressif Systems."}
</p>
<p className="flex flex-wrap items-center gap-x-5 gap-y-2">
<a href={SITE.blog} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 transition-colors hover:text-accent">
Ciência Embarcada
@@ -157,7 +415,17 @@ export default function Footer() {
lucasrguerra.dev.br
<ArrowUpRight className="h-3 w-3" aria-hidden="true" />
</a>
<span>Fontes oficiais: Espressif Systems.</span>
<span>
{isPt
? "Fontes oficiais: Espressif Systems."
: isEs
? "Fuentes oficiales: Espressif Systems."
: isFr
? "Sources officielles : Espressif Systems."
: isZh ? "官方资料来源:乐鑫(Espressif Systems)。" : isDe
? "Offizielle Quellen: Espressif Systems."
: "Official sources: Espressif Systems."}
</span>
</p>
</div>
</div>
+8
View File
@@ -0,0 +1,8 @@
// Marca do Gitea (Simple Icons, CC0). Troca o octocat nos links do repositório.
export default function GiteaMark({ className }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z" />
</svg>
);
}
+397 -58
View File
@@ -4,6 +4,9 @@ import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import Link from "next/link";
import Logo from "@/components/Logo";
import SearchDialog from "@/components/SearchDialog";
import LanguageSelector from "@/components/LanguageSelector";
import { LOCALES, getLocalizedHref } from "@/i18n/links";
import { usePathname } from "next/navigation";
import { useTheme } from "next-themes";
import {
@@ -25,7 +28,7 @@ import {
AlertTriangle,
} from "lucide-react";
const MENUS = [
const MENUS_PT = [
{
id: "hardware",
label: "Hardware",
@@ -55,7 +58,156 @@ const MENUS = [
},
];
const MOBILE_LINKS = [
const MENUS_EN = [
{
id: "hardware",
label: "Hardware",
items: [
{ href: "/series", label: "ESP32 Series", desc: "12 chips, pinouts and specifications", icon: Cpu },
{ href: "/comparacao", label: "Comparator", desc: "Up to four series side by side", icon: Scale },
{ href: "/catalogo", label: "Board Catalog", desc: "DevKits, pinouts and where to buy", icon: Box },
],
},
{
id: "tools",
label: "Tools",
items: [
{ href: "/seletor", label: "Smart Selector", desc: "The right chip for your project", icon: SlidersHorizontal },
{ href: "/diagnostico", label: "Diagnostics", desc: "Brownout, bootloop, WDT and more", icon: AlertTriangle },
{ href: "/componentes", label: "Component Registry", desc: "Drivers and idf_component.yml manifests", icon: Search },
],
},
{
id: "library",
label: "Library",
items: [
{ href: "/frameworks", label: "Frameworks & SDKs", desc: "ESP-IDF, Arduino, Rust and Matter", icon: BookOpen },
{ href: "/glossario", label: "Technical Glossary", desc: "Terms appearing in datasheets", icon: BookA },
{ href: "/sobre", label: "About the Project", desc: "Authorship, method and open source", icon: Sparkles },
],
},
];
const MENUS_ES = [
{
id: "hardware",
label: "Hardware",
items: [
{ href: "/series", label: "Series ESP32", desc: "12 chips, patillaje y especificaciones", icon: Cpu },
{ href: "/comparacao", label: "Comparador", desc: "Hasta cuatro series frente a frente", icon: Scale },
{ href: "/catalogo", label: "Catálogo de placas", desc: "DevKits, pines y dónde comprar", icon: Box },
],
},
{
id: "tools",
label: "Herramientas",
items: [
{ href: "/seletor", label: "Selector inteligente", desc: "El chip adecuado para su proyecto", icon: SlidersHorizontal },
{ href: "/diagnostico", label: "Diagnóstico", desc: "Brownout, bootloop, WDT y más", icon: AlertTriangle },
{ href: "/componentes", label: "Component Registry", desc: "Drivers y manifiestos idf_component.yml", icon: Search },
],
},
{
id: "library",
label: "Biblioteca",
items: [
{ href: "/frameworks", label: "Frameworks y SDKs", desc: "ESP-IDF, Arduino, Rust y Matter", icon: BookOpen },
{ href: "/glossario", label: "Glosario técnico", desc: "Términos que aparecen en las hojas de datos", icon: BookA },
{ href: "/sobre", label: "Acerca del proyecto", desc: "Autoría, método y código abierto", icon: Sparkles },
],
},
];
const MENUS_FR = [
{
id: "hardware",
label: "Matériel",
items: [
{ href: "/series", label: "Séries ESP32", desc: "12 puces, brochages et spécifications", icon: Cpu },
{ href: "/comparacao", label: "Comparateur", desc: "Jusqu'à quatre séries côte à côte", icon: Scale },
{ href: "/catalogo", label: "Catalogue de cartes", desc: "DevKits, broches et où acheter", icon: Box },
],
},
{
id: "tools",
label: "Outils",
items: [
{ href: "/seletor", label: "Sélecteur intelligent", desc: "La puce idéale pour votre projet", icon: SlidersHorizontal },
{ href: "/diagnostico", label: "Diagnostic", desc: "Brownout, bootloop, WDT et plus", icon: AlertTriangle },
{ href: "/componentes", label: "Component Registry", desc: "Pilotes et manifestes idf_component.yml", icon: Search },
],
},
{
id: "library",
label: "Bibliothèque",
items: [
{ href: "/frameworks", label: "Frameworks et SDKs", desc: "ESP-IDF, Arduino, Rust et Matter", icon: BookOpen },
{ href: "/glossario", label: "Glossaire technique", desc: "Les termes des fiches techniques", icon: BookA },
{ href: "/sobre", label: "À propos du projet", desc: "Auteur, méthode et open source", icon: Sparkles },
],
},
];
const MENUS_DE = [
{
id: "hardware",
label: "Hardware",
items: [
{ href: "/series", label: "ESP32-Serien", desc: "12 Chips, Pinbelegungen und Spezifikationen", icon: Cpu },
{ href: "/comparacao", label: "Vergleich", desc: "Bis zu vier Serien nebeneinander", icon: Scale },
{ href: "/catalogo", label: "Board-Katalog", desc: "DevKits, Pins und Bezugsquellen", icon: Box },
],
},
{
id: "tools",
label: "Werkzeuge",
items: [
{ href: "/seletor", label: "Intelligente Auswahl", desc: "Der richtige Chip für Ihr Projekt", icon: SlidersHorizontal },
{ href: "/diagnostico", label: "Diagnose", desc: "Brownout, Bootloops, WDT und mehr", icon: AlertTriangle },
{ href: "/componentes", label: "Component Registry", desc: "Treiber und idf_component.yml-Manifeste", icon: Search },
],
},
{
id: "library",
label: "Bibliothek",
items: [
{ href: "/frameworks", label: "Frameworks & SDKs", desc: "ESP-IDF, Arduino, Rust und Matter", icon: BookOpen },
{ href: "/glossario", label: "Technisches Glossar", desc: "Begriffe aus den Datenblättern", icon: BookA },
{ href: "/sobre", label: "Über das Projekt", desc: "Autorschaft, Methode und Open Source", icon: Sparkles },
],
},
];
const MENUS_ZH = [
{
id: "hardware",
label: "硬件",
items: [
{ href: "/series", label: "ESP32 系列", desc: "12 款芯片的引脚与规格", icon: Cpu },
{ href: "/comparacao", label: "对比工具", desc: "最多四个系列并排对比", icon: Scale },
{ href: "/catalogo", label: "开发板目录", desc: "DevKit、引脚与购买渠道", icon: Box },
],
},
{
id: "tools",
label: "工具",
items: [
{ href: "/seletor", label: "智能选型", desc: "为你的项目找到合适的芯片", icon: SlidersHorizontal },
{ href: "/diagnostico", label: "故障诊断", desc: "欠压、启动循环、看门狗等问题", icon: AlertTriangle },
{ href: "/componentes", label: "Component Registry", desc: "驱动与 idf_component.yml 清单", icon: Search },
],
},
{
id: "library",
label: "资料库",
items: [
{ href: "/frameworks", label: "框架与 SDK", desc: "ESP-IDF、Arduino、Rust 与 Matter", icon: BookOpen },
{ href: "/glossario", label: "技术术语表", desc: "数据手册中出现的术语", icon: BookA },
{ href: "/sobre", label: "关于本项目", desc: "作者、方法与开放性", icon: Sparkles },
],
},
];
const MOBILE_LINKS_PT = [
{ href: "/series", label: "Séries ESP32" },
{ href: "/comparacao", label: "Comparador" },
{ href: "/seletor", label: "Seletor inteligente" },
@@ -68,12 +220,75 @@ const MOBILE_LINKS = [
{ href: "/sobre", label: "Sobre" },
];
function isActivePath(pathname, href) {
return href === "/" ? pathname === "/" : pathname === href || String(pathname).startsWith(`${href}/`);
const MOBILE_LINKS_EN = [
{ href: "/series", label: "ESP32 Series" },
{ href: "/comparacao", label: "Comparator" },
{ href: "/seletor", label: "Smart Selector" },
{ href: "/diagnostico", label: "Diagnostics" },
{ href: "/frameworks", label: "Frameworks & SDKs" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/glossario", label: "Glossary" },
{ href: "/catalogo", label: "Board Catalog" },
{ href: "/sobre", label: "About" },
];
const MOBILE_LINKS_ES = [
{ href: "/series", label: "Series ESP32" },
{ href: "/comparacao", label: "Comparador" },
{ href: "/seletor", label: "Selector inteligente" },
{ href: "/diagnostico", label: "Diagnóstico" },
{ href: "/frameworks", label: "Frameworks y SDKs" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/glossario", label: "Glosario" },
{ href: "/catalogo", label: "Catálogo de placas" },
{ href: "/sobre", label: "Acerca de" },
];
const MOBILE_LINKS_FR = [
{ href: "/series", label: "Séries ESP32" },
{ href: "/comparacao", label: "Comparateur" },
{ href: "/seletor", label: "Sélecteur intelligent" },
{ href: "/diagnostico", label: "Diagnostic" },
{ href: "/frameworks", label: "Frameworks et SDKs" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/glossario", label: "Glossaire" },
{ href: "/catalogo", label: "Catalogue de cartes" },
{ href: "/sobre", label: "À propos" },
];
const MOBILE_LINKS_DE = [
{ href: "/series", label: "ESP32-Serien" },
{ href: "/comparacao", label: "Vergleich" },
{ href: "/seletor", label: "Intelligente Auswahl" },
{ href: "/diagnostico", label: "Diagnose" },
{ href: "/frameworks", label: "Frameworks & SDKs" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/glossario", label: "Glossar" },
{ href: "/catalogo", label: "Board-Katalog" },
{ href: "/sobre", label: "Über uns" },
];
const MOBILE_LINKS_ZH = [
{ href: "/series", label: "ESP32 系列" },
{ href: "/comparacao", label: "对比工具" },
{ href: "/seletor", label: "智能选型" },
{ href: "/diagnostico", label: "故障诊断" },
{ href: "/frameworks", label: "框架与 SDK" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/glossario", label: "术语表" },
{ href: "/catalogo", label: "开发板目录" },
{ href: "/sobre", label: "关于" },
];
function isActivePath(pathname, href, currentLocale) {
const localized = getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
if (href === "/" || localized === `/${currentLocale}/` || localized === `/${currentLocale}`) {
return pathname === `/${currentLocale}` || pathname === `/${currentLocale}/`;
}
return pathname === localized || String(pathname).startsWith(`${localized}/`);
}
export default function Header() {
const pathname = usePathname();
const pathname = usePathname() || "";
const [mounted, setMounted] = useState(false);
const [openMenu, setOpenMenu] = useState(null);
const [drawerOpen, setDrawerOpen] = useState(false);
@@ -81,6 +296,17 @@ export default function Header() {
const closeRef = useRef(null);
const menuButtonRef = useRef(null);
const currentLocale =
LOCALES.find((l) => pathname === `/${l.code}` || pathname.startsWith(`/${l.code}/`))?.code || "pt";
const isPt = currentLocale === "pt";
const isEn = currentLocale === "en";
const isEs = currentLocale === "es";
const isFr = currentLocale === "fr";
const isDe = currentLocale === "de";
const isZh = currentLocale === "zh-CN";
const getLinkHref = (href) => getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
useEffect(() => setMounted(true), []);
useEffect(() => {
@@ -117,18 +343,57 @@ export default function Header() {
};
}, [drawerOpen]);
const visibleMobileLinks = isPt
? MOBILE_LINKS_PT
: isEs
? MOBILE_LINKS_ES
: isFr
? MOBILE_LINKS_FR
: isZh ? MOBILE_LINKS_ZH : isDe
? MOBILE_LINKS_DE
: MOBILE_LINKS_EN;
const MENUS = isPt ? MENUS_PT : isEs ? MENUS_ES : isFr ? MENUS_FR : isZh ? MENUS_ZH : isDe ? MENUS_DE : MENUS_EN;
return (
<header className="sticky top-0 z-50 pt-3 sm:pt-4">
<div className="shell">
<div className="nav-pill flex h-16 items-center justify-between gap-3 rounded-full px-3 sm:px-4">
<Link href="/" className="flex min-h-11 shrink-0 items-center gap-2.5 rounded-full pl-1 pr-2" aria-label="ESPDocs, página inicial">
<div className="nav-pill flex h-16 items-center justify-between gap-1.5 rounded-full px-2.5 sm:gap-3 sm:px-4">
<Link
href={getLinkHref("/")}
className="flex min-h-11 shrink-0 items-center gap-2.5 rounded-full pl-1 pr-2"
aria-label={
isPt
? "ESPDocs, página inicial"
: isEs
? "ESPDocs, página de inicio"
: isFr
? "ESPDocs, page d'accueil"
: isZh ? "ESPDocs,首页" : isDe
? "ESPDocs, Startseite"
: "ESPDocs, homepage"
}
>
<Logo className="h-[30px] w-[30px]" />
<span className="font-display text-[1.3rem] font-semibold leading-none tracking-[-0.045em] text-ink">ESPDocs</span>
<span className="font-display text-[1.3rem] font-semibold max-[359px]:sr-only leading-none tracking-[-0.045em] text-ink">ESPDocs</span>
</Link>
<nav ref={navRef} className="hidden items-center gap-0.5 lg:flex" aria-label="Navegação principal">
<nav
ref={navRef}
className="hidden items-center gap-0.5 lg:flex"
aria-label={
isPt
? "Navegação principal"
: isEs
? "Navegación principal"
: isFr
? "Navigation principale"
: isZh ? "主导航" : isDe
? "Hauptnavigation"
: "Main navigation"
}
>
{MENUS.map((menu) => {
const active = menu.items.some((item) => isActivePath(pathname, item.href));
const active = menu.items.some((item) => isActivePath(pathname, item.href, currentLocale));
const expanded = openMenu === menu.id;
return (
<div key={menu.id} className="relative">
@@ -149,12 +414,13 @@ export default function Header() {
>
{menu.items.map((item) => {
const Icon = item.icon;
const localizedHref = getLinkHref(item.href);
return (
<Link
key={item.href}
href={item.href}
href={localizedHref}
className="group flex items-start gap-3 rounded-2xl px-3 py-3 transition-colors hover:bg-surface-2"
aria-current={isActivePath(pathname, item.href) ? "page" : undefined}
aria-current={isActivePath(pathname, item.href, currentLocale) ? "page" : undefined}
>
<span className="mt-0.5 grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-accent-soft text-accent transition-colors group-hover:bg-surface">
<Icon className="h-4 w-4" aria-hidden="true" />
@@ -172,25 +438,39 @@ export default function Header() {
);
})}
<Link href="/livro" className={`nav-link ${isActivePath(pathname, "/livro") ? "is-active" : ""}`} aria-current={isActivePath(pathname, "/livro") ? "page" : undefined}>
Livro
</Link>
<Link href="/sobre" className={`nav-link ${isActivePath(pathname, "/sobre") ? "is-active" : ""}`} aria-current={isActivePath(pathname, "/sobre") ? "page" : undefined}>
Sobre
{isPt && (
<Link href={getLinkHref("/livro")} className={`nav-link ${isActivePath(pathname, "/livro", currentLocale) ? "is-active" : ""}`} aria-current={isActivePath(pathname, "/livro", currentLocale) ? "page" : undefined}>
Livro
</Link>
)}
<Link href={getLinkHref("/sobre")} className={`nav-link ${isActivePath(pathname, "/sobre", currentLocale) ? "is-active" : ""}`} aria-current={isActivePath(pathname, "/sobre", currentLocale) ? "page" : undefined}>
{isPt ? "Sobre" : isEs ? "Acerca de" : isFr ? "À propos" : isZh ? "关于" : isDe ? "Über uns" : "About"}
</Link>
</nav>
<div className="flex items-center gap-1.5">
<Link href="/seletor" className="btn btn-primary btn-sm hidden lg:inline-flex">
<div className="flex items-center gap-1 sm:gap-1.5">
<Link href={getLinkHref("/seletor")} className="btn btn-primary btn-sm hidden lg:inline-flex">
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
Selecionar chip
{isPt ? "Selecionar chip" : isEs ? "Seleccionar chip" : isFr ? "Choisir une puce" : isZh ? "选择芯片" : isDe ? "Chip auswählen" : "Select chip"}
</Link>
<ThemeToggle />
<SearchDialog />
<LanguageSelector />
<ThemeToggle isPt={isPt} isEs={isEs} isFr={isFr} isDe={isDe} isZh={isZh} />
<button
ref={menuButtonRef}
type="button"
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:bg-surface-2 lg:hidden"
aria-label="Abrir menu de navegação"
aria-label={
isPt
? "Abrir menu de navegação"
: isEs
? "Abrir menú de navegación"
: isFr
? "Ouvrir le menu de navigation"
: isZh ? "打开导航菜单" : isDe
? "Navigationsmenü öffnen"
: "Open navigation menu"
}
aria-expanded={drawerOpen}
onClick={() => setDrawerOpen(true)}
>
@@ -213,7 +493,17 @@ export default function Header() {
<div
role="dialog"
aria-modal="true"
aria-label="Menu de navegação"
aria-label={
isPt
? "Menu de navegação"
: isEs
? "Menú de navegación"
: isFr
? "Menu de navigation"
: isZh ? "导航菜单" : isDe
? "Navigationsmenü"
: "Navigation menu"
}
aria-hidden={!drawerOpen}
inert={!drawerOpen}
className={`fixed inset-y-0 right-0 z-[101] flex w-[min(23rem,94vw)] flex-col rounded-l-[2rem] border-l border-line bg-canvas transition-transform duration-300 ${
@@ -222,52 +512,61 @@ export default function Header() {
>
<div className="flex items-start justify-between px-5 py-5">
<div>
<p className="text-xs font-semibold text-muted">Navegação</p>
<p className="mt-1 font-display text-2xl font-semibold tracking-[-0.04em] text-ink">Para onde ir</p>
<p className="text-xs font-semibold text-muted">
{isPt ? "Navegação" : isEs ? "Navegación" : isFr ? "Navigation" : isZh ? "导航" : isDe ? "Navigation" : "Navigation"}
</p>
<p className="mt-1 font-display text-2xl font-semibold tracking-[-0.04em] text-ink">
{isPt ? "Para onde ir" : isEs ? "A dónde ir" : isFr ? "Où aller" : isZh ? "前往" : isDe ? "Wohin möchten Sie" : "Where to go"}
</p>
</div>
<button
ref={closeRef}
type="button"
onClick={() => setDrawerOpen(false)}
className="grid h-10 w-10 place-items-center rounded-full border border-line text-ink transition-colors hover:bg-surface-2"
aria-label="Fechar menu"
aria-label={isPt ? "Fechar menu" : isEs ? "Cerrar menú" : isFr ? "Fermer le menu" : isZh ? "关闭菜单" : isDe ? "Menü schließen" : "Close menu"}
>
<X className="h-5 w-5" aria-hidden="true" />
</button>
</div>
<div className="px-4 pb-2">
<Link
href="/livro"
onClick={() => setDrawerOpen(false)}
className="group grid grid-cols-[3.25rem_1fr_auto] items-center gap-3 rounded-2xl bg-[#0b0d10] p-3 text-[#f4f6f8] ring-1 ring-white/10"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/livro/capa.jpg"
alt=""
aria-hidden="true"
width={52}
height={78}
className="h-[78px] w-[52px] rounded-md object-cover shadow-lg"
/>
<span className="min-w-0">
<span className="text-[0.6875rem] font-semibold text-[#75cdc1]">Livro novo</span>
<span className="mt-1 block font-display text-lg font-semibold leading-tight">Microcontroladores ESP32</span>
<span className="mt-1 block text-xs text-[#a6afbd]">Conectividade, eficiência e desempenho</span>
</span>
<ArrowRight className="h-4 w-4 shrink-0 text-[#75cdc1] transition-transform duration-300 group-hover:translate-x-1" aria-hidden="true" />
</Link>
</div>
{isPt && (
<div className="px-4 pb-2">
<Link
href="/pt/livro"
onClick={() => setDrawerOpen(false)}
className="group grid grid-cols-[3.25rem_1fr_auto] items-center gap-3 rounded-2xl bg-[#0b0d10] p-3 text-[#f4f6f8] ring-1 ring-white/10"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/livro/capa.jpg"
alt=""
aria-hidden="true"
width={52}
height={78}
className="h-[78px] w-[52px] rounded-md object-cover shadow-lg"
/>
<span className="min-w-0">
<span className="text-[0.6875rem] font-semibold text-[#75cdc1]">Livro novo</span>
<span className="mt-1 block font-display text-lg font-semibold leading-tight">Microcontroladores ESP32</span>
<span className="mt-1 block text-xs text-[#a6afbd]">Conectividade, eficiência e desempenho</span>
</span>
<ArrowRight className="h-4 w-4 shrink-0 text-[#75cdc1] transition-transform duration-300 group-hover:translate-x-1" aria-hidden="true" />
</Link>
</div>
)}
<nav className="flex-1 overflow-y-auto px-3 py-2" aria-label="Navegação móvel">
{MOBILE_LINKS.map((link) => (
<nav
className="flex-1 overflow-y-auto px-3 py-2"
aria-label={isPt ? "Navegação móvel" : isEs ? "Navegación móvil" : isFr ? "Navigation mobile" : isZh ? "移动端导航" : isDe ? "Mobile Navigation" : "Mobile navigation"}
>
{visibleMobileLinks.map((link) => (
<Link
key={link.href}
href={link.href}
href={getLinkHref(link.href)}
onClick={() => setDrawerOpen(false)}
className="group flex min-h-11 items-center justify-between gap-3 rounded-xl px-3 text-sm font-medium text-ink-soft transition-colors hover:bg-surface-2 hover:text-ink"
aria-current={isActivePath(pathname, link.href) ? "page" : undefined}
aria-current={isActivePath(pathname, link.href, currentLocale) ? "page" : undefined}
>
{link.label}
<ArrowRight className="h-4 w-4 text-faint transition-transform duration-300 group-hover:translate-x-0.5 group-hover:text-accent" aria-hidden="true" />
@@ -276,9 +575,9 @@ export default function Header() {
</nav>
<div className="p-4 pt-2">
<Link href="/seletor" onClick={() => setDrawerOpen(false)} className="btn btn-primary w-full">
<Link href={getLinkHref("/seletor")} onClick={() => setDrawerOpen(false)} className="btn btn-primary w-full">
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
Selecionar meu chip
{isPt ? "Selecionar meu chip" : isEs ? "Seleccionar mi chip" : isFr ? "Choisir ma puce" : isZh ? "选择我的芯片" : isDe ? "Meinen Chip auswählen" : "Select my chip"}
</Link>
</div>
</div>
@@ -289,7 +588,7 @@ export default function Header() {
);
}
function ThemeToggle() {
function ThemeToggle({ isPt = true, isEs = false, isFr = false, isDe = false, isZh = false }) {
const { resolvedTheme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
@@ -306,8 +605,48 @@ function ThemeToggle() {
type="button"
onClick={() => setTheme(dark ? "light" : "dark")}
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:bg-surface-2"
aria-label={dark ? "Ativar tema claro" : "Ativar tema escuro"}
title={dark ? "Tema claro" : "Tema escuro"}
aria-label={
dark
? isPt
? "Ativar tema claro"
: isEs
? "Activar tema claro"
: isFr
? "Activer le thème clair"
: isZh ? "切换到浅色主题" : isDe
? "Helles Design aktivieren"
: "Switch to light theme"
: isPt
? "Ativar tema escuro"
: isEs
? "Activar tema oscuro"
: isFr
? "Activer le thème sombre"
: isZh ? "切换到深色主题" : isDe
? "Dunkles Design aktivieren"
: "Switch to dark theme"
}
title={
dark
? isPt
? "Tema claro"
: isEs
? "Tema claro"
: isFr
? "Thème clair"
: isZh ? "浅色主题" : isDe
? "Helles Design"
: "Light theme"
: isPt
? "Tema escuro"
: isEs
? "Tema oscuro"
: isFr
? "Thème sombre"
: isZh ? "深色主题" : isDe
? "Dunkles Design"
: "Dark theme"
}
>
{dark ? <Sun className="h-4 w-4" aria-hidden="true" /> : <Moon className="h-4 w-4" aria-hidden="true" />}
</button>
+142
View File
@@ -0,0 +1,142 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { usePathname } from "next/navigation";
import { ChevronDown, Globe } from "lucide-react";
import { LOCALES, getLocalizedHref } from "@/i18n/links";
export { LOCALES, getLocalizedHref };
export default function LanguageSelector() {
if (LOCALES.length <= 1) {
return null;
}
const pathname = usePathname() || "";
const [open, setOpen] = useState(false);
const [hash, setHash] = useState("");
const containerRef = useRef(null);
// Detecta locale da URL atual
const currentLocaleCode =
LOCALES.find((l) => pathname === `/${l.code}` || pathname.startsWith(`/${l.code}/`))?.code || "pt";
const currentLocale = LOCALES.find((l) => l.code === currentLocaleCode) || LOCALES[0];
useEffect(() => {
if (typeof window !== "undefined") {
setHash(window.location.hash || "");
}
}, [pathname]);
useEffect(() => {
function onPointerDown(e) {
if (containerRef.current && !containerRef.current.contains(e.target)) {
setOpen(false);
}
}
function onKeyDown(e) {
if (e.key === "Escape") {
setOpen(false);
}
}
document.addEventListener("mousedown", onPointerDown);
document.addEventListener("keydown", onKeyDown);
return () => {
document.removeEventListener("mousedown", onPointerDown);
document.removeEventListener("keydown", onKeyDown);
};
}, []);
const handleSelect = (code) => {
if (typeof document !== "undefined") {
document.cookie = `NEXT_LOCALE=${code}; path=/; max-age=31536000; SameSite=Lax`;
}
setOpen(false);
};
return (
<div ref={containerRef} className="relative">
<button
type="button"
onClick={() => setOpen(!open)}
className="flex h-11 min-w-[44px] items-center justify-center gap-1.5 rounded-full border border-line bg-surface px-2.5 text-sm sm:px-3 font-semibold text-ink transition-colors hover:bg-surface-2 focus-visible:outline-2 focus-visible:outline-accent"
aria-haspopup="listbox"
aria-expanded={open}
aria-label={
currentLocaleCode === "en"
? `Current language: ${currentLocale.label}. Click to switch language.`
: currentLocaleCode === "es"
? `Idioma actual: ${currentLocale.label}. Haga clic para cambiar de idioma.`
: currentLocaleCode === "fr"
? `Langue actuelle : ${currentLocale.label}. Cliquez pour changer de langue.`
: currentLocaleCode === "de"
? `Aktuelle Sprache: ${currentLocale.label}. Klicken Sie, um die Sprache zu wechseln.`
: `Idioma atual: ${currentLocale.label}. Clique para trocar de idioma.`
}
title={
currentLocaleCode === "en"
? `Language: ${currentLocale.label}`
: currentLocaleCode === "fr"
? `Langue : ${currentLocale.label}`
: currentLocaleCode === "de"
? `Sprache: ${currentLocale.label}`
: `Idioma: ${currentLocale.label}`
}
>
<Globe className="hidden h-4 w-4 text-muted sm:block" aria-hidden="true" />
<span className="font-semibold">{currentLocale.short}</span>
<ChevronDown
className={`hidden h-3 w-3 text-muted transition-transform duration-200 sm:block ${open ? "rotate-180" : ""}`}
aria-hidden="true"
/>
</button>
{open && (
<div
role="listbox"
aria-label={
currentLocaleCode === "en"
? "Available languages"
: currentLocaleCode === "es"
? "Idiomas disponibles"
: currentLocaleCode === "fr"
? "Langues disponibles"
: currentLocaleCode === "de"
? "Verfügbare Sprachen"
: "Idiomas disponíveis"
}
className="absolute right-0 top-full mt-2 w-48 rounded-2xl border border-line bg-surface p-1.5 shadow-[0_24px_60px_-20px_rgba(15,23,42,0.35)] dark:shadow-[0_24px_60px_-20px_rgba(0,0,0,0.8)] z-50"
>
{LOCALES.map((loc) => {
const isActive = loc.code === currentLocaleCode;
const href = `${getLocalizedHref(pathname, loc.code)}${hash}`;
return (
<a
key={loc.code}
href={href}
lang={loc.lang}
hrefLang={loc.lang}
role="option"
aria-selected={isActive}
aria-current={isActive ? "true" : undefined}
onClick={() => handleSelect(loc.code)}
className={`flex min-h-[44px] items-center justify-between rounded-xl px-3 py-2 text-sm transition-colors ${
isActive
? "bg-accent-soft text-accent font-semibold"
: "text-ink-soft hover:bg-surface-2 hover:text-ink"
}`}
>
<span>{loc.label}</span>
<span className={`text-xs ${isActive ? "text-accent" : "text-muted"}`}>
{loc.short}
</span>
</a>
);
})}
</div>
)}
</div>
);
}
+61 -4
View File
@@ -5,14 +5,71 @@ import Link from "next/link";
* e ações. Mesma voz da /livro e da home, para que nenhuma página pareça
* de outro produto.
*/
export default function PageHero({ trail = [], icon: Icon, label, title, lede, align = "left", children }) {
export default function PageHero({
trail = [],
icon: Icon,
label,
title,
lede,
align = "left",
children,
isEn: isEnProp,
isEs: isEsProp,
isFr: isFrProp,
isDe: isDeProp,
isZh: isZhProp,
locale: localeProp,
}) {
const center = align === "center";
const isEn =
isEnProp !== undefined
? isEnProp
: localeProp
? localeProp === "en"
: trail.some((t) => t.isEn || (t.href && t.href.startsWith("/en")));
const isEs =
isEsProp !== undefined
? isEsProp
: localeProp
? localeProp === "es"
: trail.some((t) => t.isEs || (t.href && t.href.startsWith("/es")));
const isFr =
isFrProp !== undefined
? isFrProp
: localeProp
? localeProp === "fr"
: trail.some((t) => t.isFr || (t.href && t.href.startsWith("/fr")));
const isDe =
isDeProp !== undefined
? isDeProp
: localeProp
? localeProp === "de"
: trail.some((t) => t.isDe || (t.href && t.href.startsWith("/de")));
const isZh =
isZhProp !== undefined
? isZhProp
: localeProp
? localeProp === "zh-CN"
: trail.some((t) => t.isZh || (t.href && t.href.startsWith("/zh-CN")));
const homeHref = isEn ? "/en" : isEs ? "/es" : isFr ? "/fr" : isZh ? "/zh-CN" : isDe ? "/de" : "/";
const homeLabel = isEn ? "Home" : isEs ? "Inicio" : isFr ? "Accueil" : isZh ? "首页" : isDe ? "Startseite" : "Início";
const breadcrumbAria = isEn
? "Breadcrumb navigation"
: isEs
? "Navegación por migas de pan"
: isFr
? "Fil d'Ariane"
: isZh ? "面包屑导航" : isDe
? "Brotkrumennavigation"
: "Trilha de navegação";
return (
<section className="shell pt-8 sm:pt-12">
{trail.length > 0 && (
<nav aria-label="Trilha de navegação" className="flex flex-wrap items-center gap-2 text-sm text-muted">
<Link href="/" className="inline-flex min-h-11 min-w-11 items-center justify-center transition-colors hover:text-accent">
Início
<nav aria-label={breadcrumbAria} className="flex flex-wrap items-center gap-2 text-sm text-muted">
<Link href={homeHref} className="inline-flex min-h-11 min-w-11 items-center justify-center transition-colors hover:text-accent">
{homeLabel}
</Link>
{trail.map((item, i) => (
<span key={item.label} className="flex min-h-11 items-center gap-2">
+397 -20
View File
@@ -18,7 +18,7 @@ import {
* diagrama nunca divergem: corrigir um pino no JSON corrige os dois.
*/
const GRUPOS = [
const GRUPOS_PT = [
{
id: "entrada",
titulo: "Somente entrada",
@@ -26,7 +26,7 @@ const GRUPOS = [
cor: "text-accent",
explicacao:
"Aceitam apenas leitura. Não podem ser configurados como saída e não possuem resistores de pull-up ou pull-down internos. Se precisar de um, coloque no circuito.",
combina: (avisos) => /apenas de entrada|input only/.test(avisos),
combina: (avisos) => /apenas de entrada|input only/i.test(avisos),
},
{
id: "flash",
@@ -36,8 +36,8 @@ const GRUPOS = [
explicacao:
"Já estão conectados à memória de onde o firmware é lido. Usá-los como GPIO comum normalmente trava o chip ou corrompe a execução. Em módulos com flash interna eles nem chegam ao encapsulamento.",
combina: (avisos) =>
/(flash|psram)/.test(avisos) &&
/(dedicad|utilizado pela mem|não deve ser utilizado|não é recomendado)/.test(avisos),
/(flash|psram)/i.test(avisos) &&
/(dedicad|utilizado pela mem|não deve ser utilizado|não é recomendado|connected to|dedicated to|should not be used|not recommended)/i.test(avisos),
},
{
id: "strapping",
@@ -48,7 +48,7 @@ const GRUPOS = [
"O chip lê o nível destes pinos no instante do reset para decidir como inicializar. Dá para usá-los depois do boot, mas o circuito externo não pode forçar o nível errado durante o reset, senão a placa não inicia ou entra em modo de gravação sozinha.",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|modo de boot|modo de inicialização/.test(avisos),
/strapping|modo de boot|modo de inicialização|boot mode/i.test(avisos),
},
{
id: "debug",
@@ -57,7 +57,7 @@ const GRUPOS = [
cor: "text-accent",
explicacao:
"São a UART de gravação e as linhas de JTAG. Continuam utilizáveis como GPIO, mas ao reaproveitá-los você perde o caminho de gravar e depurar a placa sem desconectar o que estiver ali.",
combina: (avisos, cats) => /debugging/.test(avisos) || cats.includes("JTAG"),
combina: (avisos, cats) => /debugging|gravação/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
@@ -66,7 +66,7 @@ const GRUPOS = [
cor: "text-accent",
explicacao:
"Saem de fábrica ligados ao USB Serial/JTAG interno. Para usá-los como GPIO é preciso desativar essa função, o que também remove a gravação por USB direto.",
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/.test(avisos),
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
@@ -75,7 +75,311 @@ const GRUPOS = [
cor: "text-gold",
explicacao:
"Precisam de nível definido por hardware: pull-up externo ou circuito RC de atraso. Deixá-los soltos causa reset aleatório ou inicialização instável.",
combina: (avisos) => /flutuando/.test(avisos),
combina: (avisos) => /flutuando|floating/i.test(avisos),
},
];
const GRUPOS_EN = [
{
id: "entrada",
titulo: "Input only",
icone: ArrowDownToLine,
cor: "text-accent",
explicacao:
"Input only pins. They cannot be configured as outputs and do not have internal pull-up or pull-down resistors. If needed, add them to your external circuit.",
combina: (avisos) => /apenas de entrada|input only/i.test(avisos),
},
{
id: "flash",
titulo: "Connected to flash/PSRAM memory",
icone: HardDrive,
cor: "text-copper",
explicacao:
"Already connected to the memory where firmware is stored and executed. Using them as general-purpose GPIO typically crashes the chip or corrupts execution. In modules with internal flash, they are not brought out to the package pins.",
combina: (avisos) =>
/(flash|psram)/i.test(avisos) &&
/(dedicad|utilizado pela mem|não deve ser utilizado|não é recomendado|connected to|dedicated to|should not be used|not recommended)/i.test(avisos),
},
{
id: "strapping",
titulo: "Strapping pins (boot mode)",
icone: Power,
cor: "text-gold",
explicacao:
"The chip samples the logic level of these pins during reset to determine the boot mode. You can use them after booting, but external circuitry must not force the wrong level during reset, or the board will fail to boot or enter download mode unexpectedly.",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|modo de boot|modo de inicialização|boot mode/i.test(avisos),
},
{
id: "debug",
titulo: "Flashing and debugging",
icone: Bug,
cor: "text-accent",
explicacao:
"These are the flashing UART and JTAG lines. They can still be used as GPIO, but reusing them removes the ability to flash and debug the board without disconnecting connected peripherals.",
combina: (avisos, cats) => /debugging|gravação/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
titulo: "Native USB",
icone: Usb,
cor: "text-accent",
explicacao:
"Connected by default to the internal USB Serial/JTAG controller. Using them as GPIO requires disabling this peripheral, which also removes direct USB flashing.",
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
titulo: "Must not float",
icone: Zap,
cor: "text-gold",
explicacao:
"Require a defined hardware logic level: external pull-up or RC delay circuit. Leaving them floating causes random resets or unstable boot behavior.",
combina: (avisos) => /flutuando|floating/i.test(avisos),
},
];
const GRUPOS_ES = [
{
id: "entrada",
titulo: "Solo entrada",
icone: ArrowDownToLine,
cor: "text-accent",
explicacao:
"Aceptan únicamente lectura. No pueden configurarse como salida y no poseen resistencias de pull-up o pull-down internas. Si necesita una, agréguela en el circuito externo.",
combina: (avisos) => /solo de entrada|input[- ]only/i.test(avisos),
},
{
id: "flash",
titulo: "Conectados a la memoria flash/PSRAM",
icone: HardDrive,
cor: "text-copper",
explicacao:
"Ya están conectados a la memoria desde donde se lee el firmware. Usarlos como GPIO común normalmente bloquea el chip o corrompe la ejecución. En módulos con flash interna ni siquiera llegan a los pines del encapsulado.",
combina: (avisos) =>
/(flash|psram)/i.test(avisos) &&
/(dedicado|utilizado por la mem|no debe|no se recomienda|no recomendado|connected to|dedicated to)/i.test(avisos),
},
{
id: "strapping",
titulo: "Strapping (modo de arranque)",
icone: Power,
cor: "text-gold",
explicacao:
"El chip lee el nivel lógico de estos pines en el instante del reset para decidir cómo inicializarse. Pueden usarse después del arranque, pero el circuito externo no debe forzar el nivel incorrecto durante el reset, de lo contrario la placa no iniciará o entrará en modo de descarga inesperadamente.",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|modo de arranque|modo de inicialización|boot mode/i.test(avisos),
},
{
id: "debug",
titulo: "Grabación y depuración",
icone: Bug,
cor: "text-accent",
explicacao:
"Son la UART de grabación y las líneas de JTAG. Siguen utilizables como GPIO, pero al reutilizarlos pierde la posibilidad de grabar y depurar la placa sin desconectar lo que esté conectado allí.",
combina: (avisos, cats) => /depuración|grabación|debugging/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
titulo: "USB nativo",
icone: Usb,
cor: "text-accent",
explicacao:
"Salen de fábrica conectados al USB Serial/JTAG interno. Para usarlos como GPIO es necesario desactivar esa función, lo que también elimina la grabación por USB directo.",
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
titulo: "No deben quedar flotando",
icone: Zap,
cor: "text-gold",
explicacao:
"Requieren un nivel lógico definido por hardware: pull-up externo o circuito RC de retardo. Dejarlos sueltos causa reinicios aleatorios o un arranque inestable.",
combina: (avisos) => /flotando|floating/i.test(avisos),
},
];
const GRUPOS_FR = [
{
id: "entrada",
titulo: "Entrée uniquement",
icone: ArrowDownToLine,
cor: "text-accent",
explicacao:
"Broches en entrée seule. Elles ne peuvent pas être configurées en sortie et ne possèdent pas de résistances de pull-up ou de pull-down internes. Si vous en avez besoin, ajoutez-en dans votre circuit externe.",
combina: (avisos) => /entrée uniquement|input[- ]only/i.test(avisos),
},
{
id: "flash",
titulo: "Liées à la mémoire flash/PSRAM",
icone: HardDrive,
cor: "text-copper",
explicacao:
"Déjà connectées à la mémoire depuis laquelle le firmware est exécuté. Les utiliser comme GPIO standard plante généralement la puce ou corrompt l'exécution. Sur les modules avec flash interne, elles ne sont même pas reliées aux broches du boîtier.",
combina: (avisos) =>
/(flash|psram)/i.test(avisos) &&
/(dédi|mémoire|ne doit pas|déconseillé|connected to|dedicated to|should not)/i.test(avisos),
},
{
id: "strapping",
titulo: "Strapping (mode de démarrage)",
icone: Power,
cor: "text-gold",
explicacao:
"La puce lit l'état logique de ces broches au moment du reset pour déterminer son mode de démarrage. Vous pouvez les utiliser après le boot, mais le circuit externe ne doit pas forcer un niveau incorrect pendant le reset, sinon la carte ne démarrera pas ou entrera en mode flashage de manière inattendue.",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|mode de démarrage|démarrage|boot mode/i.test(avisos),
},
{
id: "debug",
titulo: "Programmation et débogage",
icone: Bug,
cor: "text-accent",
explicacao:
"Ce sont l'UART de programmation et les lignes JTAG. Elles restent utilisables comme GPIO, mais les réutiliser supprime la possibilité de flasher et de déboguer la carte sans déconnecter ce qui y est relié.",
combina: (avisos, cats) => /débogage|programmation|debugging/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
titulo: "USB natif",
icone: Usb,
cor: "text-accent",
explicacao:
"Reliées par défaut au contrôleur USB Série/JTAG interne. Les utiliser comme GPIO nécessite de désactiver ce périphérique, ce qui désactive également le flashage direct par USB.",
combina: (avisos) => /usb (série|serial)\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
titulo: "Ne doivent pas être laissées flottantes",
icone: Zap,
cor: "text-gold",
explicacao:
"Nécessitent un niveau logique matériel défini : pull-up externe ou circuit RC de temporisation. Les laisser flottantes entraîne des redémarrages aléatoires ou un démarrage instable.",
combina: (avisos) => /flottant|floating/i.test(avisos),
},
];
const GRUPOS_DE = [
{
id: "entrada",
titulo: "Nur Eingang",
icone: ArrowDownToLine,
cor: "text-accent",
explicacao:
"Pins, die nur als Eingang arbeiten. Sie können nicht als Ausgang konfiguriert werden und besitzen keine internen Pull-up- oder Pull-down-Widerstände. Falls erforderlich, sehen Sie diese in Ihrer externen Schaltung vor.",
combina: (avisos) => /nur eingang|input[- ]only/i.test(avisos),
},
{
id: "flash",
titulo: "Mit Flash-/PSRAM-Speicher verbunden",
icone: HardDrive,
cor: "text-copper",
explicacao:
"Bereits mit dem Speicher verbunden, aus dem die Firmware ausgeführt wird. Die Verwendung als universelle GPIOs führt meist zu Abstürzen oder Speicherbeschädigungen. Bei Modulen mit internem Flash sind sie nicht nach außen geführt.",
combina: (avisos) =>
/(flash|psram)/i.test(avisos) &&
/(dediziert|speicher|sollte nicht|nicht empfohlen|connected to|dedicated to|should not)/i.test(avisos),
},
{
id: "strapping",
titulo: "Strapping-Pins (Bootmodus)",
icone: Power,
cor: "text-gold",
explicacao:
"Der Chip liest den Logikpegel dieser Pins beim Reset aus, um den Bootmodus festzulegen. Nach dem Booten können sie genutzt werden, die externe Schaltung darf beim Reset jedoch keinen falschen Pegel erzwingen, da das Board sonst nicht startet oder unerwartet in den Download-Modus wechselt.",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|bootmodus|boot-modus|boot mode/i.test(avisos),
},
{
id: "debug",
titulo: "Programmierung und Debugging",
icone: Bug,
cor: "text-accent",
explicacao:
"Dies sind die Flash-UART- und JTAG-Leitungen. Sie können als GPIO genutzt werden, doch dadurch entfällt die Möglichkeit, das Board ohne Trennen der Peripherie zu programmieren oder zu debuggen.",
combina: (avisos, cats) => /debugging|programmierung/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
titulo: "Natives USB",
icone: Usb,
cor: "text-accent",
explicacao:
"Standardmäßig mit dem internen USB-Serial/JTAG-Controller verbunden. Um sie als GPIO zu nutzen, muss diese Funktion deaktiviert werden, wodurch auch das direkte Flashen über USB entfällt.",
combina: (avisos) => /usb[- ](serial|seriell)\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
titulo: "Dürfen nicht unbeschaltet bleiben",
icone: Zap,
cor: "text-gold",
explicacao:
"Erfordern einen definierten Hardwarepegel: externen Pull-up oder RC-Verzögerungsschaltung. Bleiben sie unbeschaltet (floating), führt dies zu sporadischen Resets oder instabilem Bootverhalten.",
combina: (avisos) => /unbeschaltet|floating/i.test(avisos),
},
];
const GRUPOS_ZH = [
{
id: "entrada",
titulo: "仅输入",
icone: ArrowDownToLine,
cor: "text-accent",
explicacao:
"仅能作输入的引脚。它们不能配置为输出,也没有内部上拉或下拉电阻。如有需要,请在外部电路中添加。",
combina: (avisos) => /仅为输入|仅输入|input[- ]only/i.test(avisos),
},
{
id: "flash",
titulo: "连接到闪存/PSRAM",
icone: HardDrive,
cor: "text-copper",
explicacao:
"已连接到存放并执行固件的存储器。把它们当作通用 GPIO 使用,通常会使芯片崩溃或破坏程序执行。在带内置闪存的模组中,这些引脚不会引出到封装引脚上。",
combina: (avisos) =>
/(flash|psram)/i.test(avisos) &&
/(专用于|存储使用|不得用于|不建议|dedicated to)/i.test(avisos),
},
{
id: "strapping",
titulo: "启动配置引脚(Strapping,启动模式)",
icone: Power,
cor: "text-gold",
explicacao:
"芯片在复位期间会对这些引脚的逻辑电平采样,以决定启动模式。启动完成后可以使用它们,但外部电路在复位期间不能把它们强制到错误的电平,否则开发板将无法启动,或意外进入下载模式。",
combina: (avisos, cats) =>
cats.includes("Strapping") ||
/strapping|启动模式|启动配置|boot mode/i.test(avisos),
},
{
id: "debug",
titulo: "烧录与调试",
icone: Bug,
cor: "text-accent",
explicacao:
"这些是用于烧录的 UART 和 JTAG 线。它们仍可用作 GPIO,但一旦复用,就必须先断开所接外设,才能对开发板烧录和调试。",
combina: (avisos, cats) => /调试|烧录|debugging/i.test(avisos) || cats.includes("JTAG"),
},
{
id: "usb",
titulo: "原生 USB",
icone: Usb,
cor: "text-accent",
explicacao:
"默认连接到内部的 USB Serial/JTAG 控制器。要把它们用作 GPIO,就必须禁用该外设,同时也会失去直接通过 USB 烧录的能力。",
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
},
{
id: "eletrico",
titulo: "不能悬空",
icone: Zap,
cor: "text-gold",
explicacao:
"需要确定的硬件逻辑电平:外部上拉或 RC 延时电路。悬空会导致随机复位或启动不稳定。",
combina: (avisos) => /浮空|悬空|floating/i.test(avisos),
},
];
@@ -85,8 +389,17 @@ function rotuloDoPino(pino) {
return gpio && gpio !== pino.nome ? `${pino.nome} · ${gpio}` : pino.nome;
}
function derivarGrupos(conexoes) {
return GRUPOS.map((grupo) => {
function derivarGrupos(conexoes, isEn, isEs, isFr, isDe, isZh = false) {
const listaGrupos = isEn
? GRUPOS_EN
: isEs
? GRUPOS_ES
: isFr
? GRUPOS_FR
: isZh ? GRUPOS_ZH : isDe
? GRUPOS_DE
: GRUPOS_PT;
return listaGrupos.map((grupo) => {
const vistos = new Map();
for (const pino of conexoes) {
if (!["io", "analog", "dedicated"].includes(pino.tipo)) continue;
@@ -101,10 +414,16 @@ function derivarGrupos(conexoes) {
}).filter((g) => g.pinos.length > 0);
}
export default function PinRestrictions({ conexoes, serieKey }) {
export default function PinRestrictions({ conexoes, serieKey, isEn = false, isEs = false, isFr = false, isDe = false, isZh = false, locale }) {
if (!conexoes?.length) return null;
const grupos = derivarGrupos(conexoes);
const effectiveIsEn = isEn || locale === "en";
const effectiveIsEs = isEs || locale === "es";
const effectiveIsFr = isFr || locale === "fr";
const effectiveIsDe = isDe || locale === "de";
const effectiveIsZh = isZh || locale === "zh-CN";
const grupos = derivarGrupos(conexoes, effectiveIsEn, effectiveIsEs, effectiveIsFr, effectiveIsDe, effectiveIsZh);
if (!grupos.length) return null;
const totalPinos = new Set(grupos.flatMap((g) => g.pinos)).size;
@@ -115,13 +434,43 @@ export default function PinRestrictions({ conexoes, serieKey }) {
<span className="grid h-9 w-9 place-items-center rounded-full bg-gold-soft text-gold">
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
</span>
Pinos com restrição de uso
{effectiveIsEn
? "Pins with usage restrictions"
: effectiveIsEs
? "Pines con restricción de uso"
: effectiveIsFr
? "Broches avec restrictions d'utilisation"
: effectiveIsZh ? "有使用限制的引脚" : effectiveIsDe
? "Pins mit Nutzungseinschränkungen"
: "Pinos com restrição de uso"}
</h2>
<p className="mt-3 max-w-3xl text-sm leading-relaxed text-muted">
Nem todo pino do {serieKey} está livre para uso geral. {totalPinos} deles têm alguma
condição: já estão ocupados por memória, são lidos durante o boot ou só funcionam
como entrada. Vale conferir antes de fechar o esquemático.
{effectiveIsEn ? (
<>
Not every pin on the {serieKey} is free for general-purpose use. {totalPinos} of them have conditions: occupied by memory, sampled during boot, or function as input only. Check before finalizing your schematic.
</>
) : effectiveIsEs ? (
<>
No todos los pines del {serieKey} están libres para uso general. {totalPinos} de ellos tienen alguna condición: ya están ocupados por memoria, se leen durante el arranque o solo funcionan como entrada. Conviene comprobarlos antes de cerrar el esquemático.
</>
) : effectiveIsFr ? (
<>
Toutes les broches de l&apos;{serieKey} ne sont pas libres pour un usage général. {totalPinos} d&apos;entre elles ont des conditions : occupées par la mémoire, lues pendant le démarrage ou fonctionnent uniquement en entrée. Pensez à vérifier avant de finaliser votre schéma.
</>
) : effectiveIsZh ? ( <>
{serieKey} 上并非每个引脚都可以随意用作通用 IO。其中有 {totalPinos} 个带有使用条件:被存储器占用、在启动时被读取,或只能作输入。在定稿原理图之前,建议先核对一遍。
</> ) : effectiveIsDe ? (
<>
Nicht jeder Pin des {serieKey} steht für allgemeine Zwecke frei zur Verfügung. {totalPinos} davon unterliegen Bedingungen: durch Speicher belegt, beim Booten abgefragt oder reine Eingangspins. Prüfen Sie dies vor Abschluss Ihres Schaltplans.
</>
) : (
<>
Nem todo pino do {serieKey} está livre para uso geral. {totalPinos} deles têm alguma
condição: já estão ocupados por memória, são lidos durante o boot ou só funcionam
como entrada. Vale conferir antes de fechar o esquemático.
</>
)}
</p>
<div className="mt-6 grid gap-4 md:grid-cols-2">
@@ -131,7 +480,26 @@ export default function PinRestrictions({ conexoes, serieKey }) {
<Icone className={`h-4 w-4 shrink-0 ${corIcone}`} aria-hidden="true" />
<h3 className="text-sm font-semibold text-ink">{titulo}</h3>
<span className="ml-auto text-xs text-muted tabular-nums">
{pinos.length} {pinos.length === 1 ? "pino" : "pinos"}
{pinos.length}{" "}
{pinos.length === 1
? effectiveIsEn
? "pin"
: effectiveIsEs
? "pin"
: effectiveIsFr
? "broche"
: effectiveIsZh ? "个引脚" : effectiveIsDe
? "Pin"
: "pino"
: effectiveIsEn
? "pins"
: effectiveIsEs
? "pines"
: effectiveIsFr
? "broches"
: effectiveIsZh ? "个引脚" : effectiveIsDe
? "Pins"
: "pinos"}
</span>
</div>
@@ -150,11 +518,20 @@ export default function PinRestrictions({ conexoes, serieKey }) {
<div className="mt-6 flex flex-col justify-between gap-4 border-t border-line pt-5 sm:flex-row sm:items-center">
<p className="max-w-xl text-sm leading-relaxed text-muted">
Estes grupos vêm dos mesmos dados do diagrama de conexões. Lá você vê pino a pino
todas as funções, o domínio de alimentação e os avisos completos.
{effectiveIsEn ? (
"These groups are derived from the same data as the pinout diagram. There you can see every pin's full functions, power domain, and complete engineering notes."
) : effectiveIsEs ? (
"Estos grupos proceden de los mismos datos que el diagrama de conexiones. Allí podrá consultar pino a pino todas las funciones, el dominio de alimentación y los avisos completos."
) : effectiveIsFr ? (
"Ces groupes sont issus des mêmes données que le schéma de brochage. Vous pouvez y consulter broche par broche l'ensemble des fonctions, le domaine d'alimentation et les remarques complètes."
) : effectiveIsZh ? ( "这些分组来自与连接图相同的数据。在那里可以逐个引脚查看全部功能、供电域和完整的警告。" ) : effectiveIsDe ? (
"Diese Gruppen stammen aus denselben Daten wie das Pinbelegungsdiagramm. Dort finden Sie für jeden Pin alle Funktionen, den Spannungsbereich und die vollständigen Entwicklungshinweise."
) : (
"Estes grupos vêm dos mesmos dados do diagrama de conexões. Lá você vê pino a pino todas as funções, o domínio de alimentação e os avisos completos."
)}
</p>
<Link href="#connections" className="btn btn-ghost shrink-0">
Abrir diagrama de pinos
{effectiveIsEn ? "Open pinout diagram" : effectiveIsEs ? "Abrir diagrama de pines" : effectiveIsFr ? "Ouvrir le brochage" : effectiveIsZh ? "打开引脚图" : effectiveIsDe ? "Pinbelegung öffnen" : "Abrir diagrama de pinos"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
+551
View File
@@ -0,0 +1,551 @@
"use client";
import { useState, useEffect, useRef, useMemo, useCallback } from "react";
import { createPortal } from "react-dom";
import { useRouter, usePathname } from "next/navigation";
import {
Search,
X,
CornerDownLeft,
ArrowUp,
ArrowDown,
FileText,
Cpu,
Terminal,
BookOpen,
AlertTriangle,
Box,
Sparkles,
Plug,
} from "lucide-react";
import { preparar, buscar, EXEMPLOS_DE_BUSCA } from "@/lib/searchEngine";
import { normalizar } from "@/lib/searchTopics";
const TIPOS_PT = {
resposta: { label: "Resposta", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "Pinos", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "Página", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "Série", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "Framework", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "Glossário", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "Erro", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "Componente", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const TIPOS_EN = {
resposta: { label: "Answer", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "Pins", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "Page", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "Series", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "Framework", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "Glossary", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "Error", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "Component", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const TIPOS_ES = {
resposta: { label: "Respuesta", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "Pines", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "Página", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "Serie", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "Framework", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "Glosario", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "Error", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "Componente", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const TIPOS_FR = {
resposta: { label: "Réponse", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "Broches", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "Page", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "Série", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "Framework", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "Glossaire", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "Erreur", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "Composant", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const TIPOS_DE = {
resposta: { label: "Antwort", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "Pins", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "Seite", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "Serie", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "Framework", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "Glossar", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "Fehler", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "Komponente", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const TIPOS_ZH = {
resposta: { label: "答案", Icon: Sparkles, cor: "bg-accent text-accent-contrast" },
pino: { label: "引脚", Icon: Plug, cor: "bg-accent text-accent-contrast" },
pagina: { label: "页面", Icon: FileText, cor: "bg-surface-2 text-ink-soft" },
serie: { label: "系列", Icon: Cpu, cor: "bg-accent-soft text-accent" },
framework: { label: "框架", Icon: Terminal, cor: "bg-teal-soft text-teal" },
glossario: { label: "术语", Icon: BookOpen, cor: "bg-copper-soft text-copper" },
erro: { label: "错误", Icon: AlertTriangle, cor: "bg-gold-soft text-gold" },
componente: { label: "组件", Icon: Box, cor: "bg-surface-2 text-ink-soft" },
};
const INTELIGENTES = new Set(["resposta", "pino"]);
const EXEMPLOS_EN = ["flash s3", "usb pins c6", "gpio0 esp32", "brownout", "LVGL", "FreeRTOS"];
const EXEMPLOS_ES = ["flash s3", "pines usb c6", "gpio0 esp32", "brownout", "LVGL", "FreeRTOS"];
const EXEMPLOS_FR = ["flash s3", "broches usb c6", "gpio0 esp32", "brownout", "LVGL", "FreeRTOS"];
const EXEMPLOS_DE = ["flash s3", "usb pins c6", "gpio0 esp32", "brownout", "LVGL", "FreeRTOS"];
const EXEMPLOS_ZH = ["s3 闪存", "c6 usb 引脚", "esp32 gpio0", "brownout", "LVGL", "FreeRTOS"];
function Destaque({ texto, termos }) {
if (!termos.length) return texto;
const norm = normalizar(texto);
if (norm.length !== texto.length) return texto;
const marcas = new Array(texto.length).fill(false);
for (const t of termos) {
let i = norm.indexOf(t);
while (i !== -1) {
for (let k = i; k < i + t.length; k++) marcas[k] = true;
i = norm.indexOf(t, i + t.length);
}
}
const partes = [];
let atual = "";
let marcado = false;
for (let i = 0; i < texto.length; i++) {
if (marcas[i] !== marcado && atual) {
partes.push({ t: atual, m: marcado });
atual = "";
}
marcado = marcas[i];
atual += texto[i];
}
if (atual) partes.push({ t: atual, m: marcado });
return partes.map((p, i) =>
p.m ? (
<mark key={i} className="rounded-sm bg-accent-soft px-0.5 text-accent">
{p.t}
</mark>
) : (
<span key={i}>{p.t}</span>
)
);
}
function Pilula({ children, onClick, forte = false }) {
const base = "rounded-full px-2.5 py-1 text-xs font-semibold";
if (!onClick) return <span className={`${base} ${forte ? "bg-accent text-accent-contrast" : "bg-accent-soft text-accent"}`}>{children}</span>;
return (
<button
type="button"
onClick={onClick}
className={`${base} cursor-pointer border border-line bg-surface text-ink-soft transition-colors hover:border-accent hover:text-accent`}
>
{children}
</button>
);
}
export default function SearchDialog() {
const pathname = usePathname() || "";
const locale = pathname === "/en" || pathname.startsWith("/en/")
? "en"
: pathname === "/es" || pathname.startsWith("/es/")
? "es"
: pathname === "/fr" || pathname.startsWith("/fr/")
? "fr"
: pathname === "/de" || pathname.startsWith("/de/")
? "de"
: pathname === "/zh-CN" || pathname.startsWith("/zh-CN/")
? "zh-CN"
: "pt";
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const TIPOS = isEn ? TIPOS_EN : isEs ? TIPOS_ES : isFr ? TIPOS_FR : isZh ? TIPOS_ZH : isDe ? TIPOS_DE : TIPOS_PT;
const EXEMPLOS = isEn ? EXEMPLOS_EN : isEs ? EXEMPLOS_ES : isFr ? EXEMPLOS_FR : isZh ? EXEMPLOS_ZH : isDe ? EXEMPLOS_DE : EXEMPLOS_DE_BUSCA;
const [aberto, setAberto] = useState(false);
const [montado, setMontado] = useState(false);
const [consulta, setConsulta] = useState("");
const [indice, setIndice] = useState(null);
const [erro, setErro] = useState(false);
const [ativo, setAtivo] = useState(0);
const inputRef = useRef(null);
const listaRef = useRef(null);
const router = useRouter();
useEffect(() => setMontado(true), []);
const fechar = useCallback(() => {
setAberto(false);
setConsulta("");
setAtivo(0);
}, []);
// Atalhos globais: Ctrl/⌘+K abre; "/" abre fora de campos de texto.
useEffect(() => {
function onKey(e) {
const emCampo = /^(INPUT|TEXTAREA|SELECT)$/.test(e.target?.tagName) || e.target?.isContentEditable;
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
setAberto((v) => !v);
} else if (e.key === "/" && !emCampo && !e.ctrlKey && !e.metaKey && !e.altKey) {
e.preventDefault();
setAberto(true);
} else if (e.key === "Escape") {
fechar();
}
}
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [fechar]);
const carregarIndice = useCallback(() => {
setErro(false);
let cancelado = false;
const url = isEn
? "/api/busca/en?v=2"
: isEs
? "/api/busca/es?v=2"
: isFr
? "/api/busca/fr?v=2"
: isZh ? "/api/busca/zh-CN?v=2" : isDe
? "/api/busca/de?v=2"
: "/api/busca?v=2";
fetch(url, { cache: "no-cache" })
.then((r) => {
if (!r.ok) {
// Fallback para /api/busca caso a rota dinâmica do locale falhe
return fetch("/api/busca?v=2", { cache: "no-cache" }).then((r2) => {
if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
return r2.json();
});
}
return r.json();
})
.then((dados) => {
if (!cancelado) {
setIndice(preparar(dados));
}
})
.catch((err) => {
console.error("Erro ao carregar índice de busca:", err);
if (!cancelado) setErro(true);
});
return () => {
cancelado = true;
};
}, [isEn, isEs, isFr, isDe, isZh]);
// Carrega o índice (textos + especificações + pinos) na primeira abertura.
useEffect(() => {
if (!aberto || indice) return;
return carregarIndice();
}, [aberto, indice, carregarIndice]);
useEffect(() => {
if (aberto) {
document.body.style.overflow = "hidden";
inputRef.current?.focus();
}
return () => {
document.body.style.overflow = "";
};
}, [aberto]);
const termos = useMemo(() => normalizar(consulta).split(/\s+/).filter((t) => t.length > 1), [consulta]);
const busca = useMemo(() => {
if (!indice) return { resultados: [], interpretacao: { chips: [], topicos: [] }, sugestoes: [], totalRespostas: 0 };
if (!consulta.trim()) {
return { resultados: indice.itens.filter((i) => i.tipo === "pagina"), interpretacao: { chips: [], topicos: [] }, sugestoes: [], totalRespostas: 0 };
}
return buscar(indice, consulta);
}, [indice, consulta]);
const { resultados, interpretacao, sugestoes } = busca;
const vazia = !consulta.trim();
useEffect(() => setAtivo(0), [consulta]);
useEffect(() => {
listaRef.current?.querySelector(`[data-idx="${ativo}"]`)?.scrollIntoView({ block: "nearest" });
}, [ativo]);
function ir(item) {
if (!item) return;
fechar();
router.push(item.href);
if (item.href.includes("#")) setTimeout(() => window.dispatchEvent(new HashChangeEvent("hashchange")), 80);
}
function anexar(termo) {
setConsulta((c) => `${c.trim()} ${termo}`.trim());
inputRef.current?.focus();
}
function onInputKey(e) {
if (e.key === "ArrowDown") {
e.preventDefault();
setAtivo((i) => Math.min(i + 1, resultados.length - 1));
} else if (e.key === "ArrowUp") {
e.preventDefault();
setAtivo((i) => Math.max(i - 1, 0));
} else if (e.key === "Enter") {
e.preventDefault();
ir(resultados[ativo]);
}
}
const entendeu = interpretacao.chips.length > 0 || interpretacao.topicos.length > 0;
return (
<>
<button
type="button"
id="botao-busca"
onClick={() => setAberto(true)}
className="flex h-11 min-w-11 shrink-0 cursor-pointer items-center justify-center gap-2 rounded-full border border-line px-3 text-ink transition-colors hover:bg-surface-2 xl:px-4"
aria-label={isEn ? "Search ESPDocs (Ctrl+K)" : isEs ? "Buscar en ESPDocs (Ctrl+K)" : isFr ? "Rechercher sur ESPDocs (Ctrl+K)" : isZh ? "在 ESPDocs 中搜索(Ctrl+K)" : isDe ? "ESPDocs durchsuchen (Strg+K)" : "Buscar no ESPDocs (Ctrl+K)"}
>
<Search className="h-4 w-4" aria-hidden="true" />
<span className="hidden text-sm font-medium xl:inline">{isEn ? "Search" : isEs ? "Buscar" : isFr ? "Rechercher" : isZh ? "搜索" : isDe ? "Suchen" : "Buscar"}</span>
<kbd className="hidden rounded-md border border-line bg-surface-2 px-1.5 py-0.5 font-mono text-xs font-semibold text-muted xl:inline">{isZh ? "Ctrl K" : isDe ? "Strg K" : "Ctrl K"}</kbd>
</button>
{montado &&
aberto &&
createPortal(
<div className="fixed inset-0 z-[120] flex items-start justify-center px-4 pt-[8vh]" role="dialog" aria-modal="true" aria-label={isEn ? "Search ESPDocs" : isEs ? "Buscar en ESPDocs" : isFr ? "Rechercher sur ESPDocs" : isZh ? "在 ESPDocs 中搜索" : isDe ? "ESPDocs durchsuchen" : "Buscar no ESPDocs"}>
<div className="dialog-scrim absolute inset-0 bg-black/45 backdrop-blur-sm" onClick={fechar} />
<div className="dialog-panel relative flex max-h-[80vh] w-full max-w-2xl flex-col overflow-hidden rounded-3xl border border-line bg-canvas shadow-2xl">
<div className="flex items-center gap-3 border-b border-line px-5">
<Search className="h-5 w-5 shrink-0 text-accent" aria-hidden="true" />
<input
ref={inputRef}
id="campo-busca"
type="text"
value={consulta}
onChange={(e) => setConsulta(e.target.value)}
onKeyDown={onInputKey}
placeholder={
isEn
? "Ask ESPDocs: “flash s3”, “usb pins c6”, “gpio0 esp32”…"
: isEs
? "Pregunte a ESPDocs: “flash s3”, “pines usb c6”, “gpio0 esp32”…"
: isFr
? "Demandez à ESPDocs : « flash s3 », « broches usb c6 », « gpio0 esp32 »…"
: isZh ? "向 ESPDocs 提问:“s3 闪存”、“c6 usb 引脚”、“esp32 gpio0”…" : isDe
? "ESPDocs fragen: „flash s3“, „usb pins c6“, „gpio0 esp32“… "
: "Pergunte ao ESPDocs: “flash s3”, “pinos usb c6”, “gpio0 esp32”…"
}
className="flex-1 bg-transparent py-5 text-base text-ink outline-none placeholder:text-muted"
autoComplete="off"
spellCheck={false}
aria-label={isEn ? "Search query" : isEs ? "Término de búsqueda" : isFr ? "Requête de recherche" : isZh ? "搜索词" : isDe ? "Suchbegriff" : "Termo de busca"}
/>
<button
type="button"
onClick={fechar}
className="grid h-9 w-9 cursor-pointer place-items-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-ink"
aria-label={isEn ? "Close search" : isEs ? "Cerrar búsqueda" : isFr ? "Fermer la recherche" : isZh ? "关闭搜索" : isDe ? "Suche schließen" : "Fechar busca"}
>
<X className="h-4 w-4" />
</button>
</div>
{entendeu && (
<div className="flex flex-wrap items-center gap-2 border-b border-line bg-surface px-5 py-2.5">
<span className="text-xs font-semibold text-muted">{isEn ? "Understood:" : isEs ? "Entendido:" : isFr ? "Compris :" : isZh ? "理解为:" : isDe ? "Erkannt:" : "Entendi:"}</span>
{interpretacao.chips.map((c) => (
<Pilula key={c.chave} forte>{c.nome}</Pilula>
))}
{interpretacao.topicos.map((t) => (
<Pilula key={t.id}>{t.nome}</Pilula>
))}
</div>
)}
{sugestoes.length > 0 && (
<div className="flex flex-wrap items-center gap-2 border-b border-line px-5 py-2.5">
<span className="text-xs font-semibold text-muted">
{interpretacao.chips.length
? (isEn ? "Ask about:" : isEs ? "Preguntar sobre:" : isFr ? "Poser une question sur :" : isZh ? "查询:" : isDe ? "Frage zu:" : "Perguntar sobre:")
: (isEn ? "Which chip?" : isEs ? "¿Para qué chip?" : isFr ? "Pour quelle puce ?" : isZh ? "针对哪款芯片?" : isDe ? "Für welchen Chip?" : "Para qual chip?")}
</span>
{sugestoes.map((s) => (
<Pilula key={s.rotulo} onClick={() => anexar(s.anexar)}>
{s.rotulo}
</Pilula>
))}
</div>
)}
<div ref={listaRef} className="flex-1 overflow-y-auto p-2" role="listbox">
{erro && (
<div className="p-6 text-center">
<p className="text-sm font-semibold text-danger">
{isEn
? "Could not load search index."
: isEs
? "No se pudo cargar el índice de búsqueda."
: isFr
? "Impossible de charger l'index de recherche."
: isZh ? "无法加载搜索索引。" : isDe
? "Suchindex konnte nicht geladen werden."
: "Não foi possível carregar o índice de busca."}
</p>
<button
type="button"
onClick={carregarIndice}
className="btn btn-primary btn-sm mt-3"
>
{isEn ? "Try again" : isEs ? "Reintentar" : isFr ? "Réessayer" : isZh ? "重试" : isDe ? "Erneut versuchen" : "Tentar novamente"}
</button>
</div>
)}
{!erro && !indice && (
<p className="p-6 text-center text-sm text-muted">
{isEn ? "Loading…" : isEs ? "Cargando…" : isFr ? "Chargement…" : isZh ? "加载中…" : isDe ? "Wird geladen…" : "Carregando…"}
</p>
)}
{indice && vazia && (
<div className="px-3 pb-3 pt-1">
<p className="text-xs font-semibold text-muted">
{isEn ? "Try asking" : isEs ? "Pruebe a preguntar" : isFr ? "Essayez de demander" : isZh ? "试着问问" : isDe ? "Versuchen Sie" : "Experimente perguntar"}
</p>
<div className="mt-2 flex flex-wrap gap-2">
{EXEMPLOS.map((ex) => (
<Pilula key={ex} onClick={() => setConsulta(ex)}>
{ex}
</Pilula>
))}
</div>
<p className="mt-4 text-xs font-semibold text-muted">
{isEn ? "Go to" : isEs ? "Ir a" : isFr ? "Aller à" : isZh ? "前往" : isDe ? "Gehe zu" : "Ir para"}
</p>
</div>
)}
{indice && !vazia && resultados.length === 0 && (
<div className="p-8 text-center">
<p className="font-display text-lg font-semibold text-ink">
{isEn
? `No results for “${consulta}”`
: isEs
? `Sin resultados para “${consulta}”`
: isFr
? `Aucun résultat pour « ${consulta} »`
: isZh ? `未找到“${consulta}”的结果` : isDe
? `Keine Ergebnisse für „${consulta}“`
: `Nenhum resultado para “${consulta}”`}
</p>
<p className="mt-1 text-sm text-muted">
{isEn
? "Try “brownout”, “flash s3”, “usb pins c6” or “LVGL”."
: isEs
? "Pruebe “brownout”, “flash s3”, “pines usb c6” o “LVGL”."
: isFr
? "Essayez « brownout », « flash s3 », « broches usb c6 » ou « LVGL »."
: isZh ? "试试“brownout”、“s3 闪存”、“c6 usb 引脚”或“LVGL”。" : isDe
? "Versuchen Sie „brownout“, „flash s3“, „usb pins c6“ oder „LVGL“."
: "Tente “brownout”, “flash s3”, “pinos usb c6” ou “LVGL”."}
</p>
</div>
)}
{resultados.map((item, idx) => {
const { Icon, label, cor } = TIPOS[item.tipo] ?? TIPOS.pagina;
const sel = idx === ativo;
const inteligente = INTELIGENTES.has(item.tipo);
return (
<button
key={`${item.id}-${idx}`}
type="button"
role="option"
aria-selected={sel}
data-idx={idx}
onMouseMove={() => setAtivo(idx)}
onClick={() => ir(item)}
className={`flex w-full cursor-pointer items-start gap-3 rounded-2xl p-3 text-left transition-colors ${
sel ? "bg-surface-2" : ""
} ${inteligente ? "my-1 border border-line" : ""}`}
>
<div className={`grid h-9 w-9 shrink-0 place-items-center rounded-xl ${cor}`}>
<Icon className="h-4 w-4" aria-hidden="true" />
</div>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<span className="truncate text-sm font-semibold text-ink">
{inteligente ? item.titulo : <Destaque texto={item.titulo} termos={termos} />}
</span>
<span className={`shrink-0 rounded-full px-2 py-0.5 text-xs font-semibold ${inteligente ? "bg-accent-soft text-accent" : cor}`}>{label}</span>
</div>
<p className="mt-0.5 line-clamp-2 text-xs leading-relaxed text-muted">
{inteligente ? item.descricao : <Destaque texto={item.descricao} termos={termos} />}
</p>
{item.linhas && (
<dl className="mt-2 grid gap-x-4 gap-y-1 text-xs sm:grid-cols-[auto_1fr]">
{item.linhas.map((l) => (
<div key={l.k} className="contents">
<dt className="font-semibold text-ink-soft">{l.k}</dt>
<dd className="text-ink">{l.v}</dd>
</div>
))}
</dl>
)}
{item.chips && (
<div className="mt-2 flex flex-wrap gap-1.5">
{item.chips.map((c) => (
<span key={c} className="rounded-md border border-line bg-surface px-1.5 py-0.5 font-mono text-xs text-ink-soft">
{c}
</span>
))}
</div>
)}
</div>
{sel && <CornerDownLeft className="mt-2 h-4 w-4 shrink-0 text-accent" aria-hidden="true" />}
</button>
);
})}
</div>
<div className="hidden items-center gap-4 border-t border-line bg-surface px-4 py-2.5 text-xs text-muted md:flex">
<span className="flex items-center gap-1"><ArrowUp className="h-3 w-3" /><ArrowDown className="h-3 w-3" /> {isEn ? "navigate" : isEs ? "navegar" : isFr ? "naviguer" : isZh ? "导航" : isDe ? "navigieren" : "navegar"}</span>
<span className="flex items-center gap-1"><CornerDownLeft className="h-3 w-3" /> {isEn ? "open" : isEs ? "abrir" : isFr ? "ouvrir" : isZh ? "打开" : isDe ? "öffnen" : "abrir"}</span>
<span><kbd className="font-mono font-semibold">Esc</kbd> {isEn ? "close" : isEs ? "cerrar" : isFr ? "fermer" : isZh ? "关闭" : isDe ? "schließen" : "fechar"}</span>
<span className="ml-auto">
{vazia
? (isEn
? "Tip: press / on any page"
: isEs
? "Consejo: presione / en cualquier página"
: isFr
? "Astuce : appuyez sur / sur n'importe quelle page"
: isZh ? "提示:在任意页面按 / 键" : isDe
? "Tipp: Drücken Sie / auf einer beliebigen Seite"
: "Dica: pressione / em qualquer página")
: `${resultados.length} ${
isEn
? "result(s)"
: isEs
? "resultado(s)"
: isFr
? "résultat(s)"
: isZh ? "条结果" : isDe
? "Ergebnis(se)"
: "resultado(s)"
}`}
</span>
</div>
</div>
</div>,
document.body
)}
</>
);
}
+23 -2
View File
@@ -2,7 +2,12 @@
import { useEffect, useRef, useState } from "react";
export default function SeriesTabMenu({ tabs }) {
export default function SeriesTabMenu({ tabs, isEn = false, isEs = false, isFr = false, isDe = false, isZh = false, locale }) {
const effectiveIsEn = isEn || locale === "en";
const effectiveIsEs = isEs || locale === "es";
const effectiveIsFr = isFr || locale === "fr";
const effectiveIsDe = isDe || locale === "de";
const effectiveIsZh = isZh || locale === "zh-CN";
const availableTabs = tabs.filter((tab) => tab.available);
const [activeTab, setActiveTab] = useState(availableTabs[0]?.id);
const refs = useRef({});
@@ -59,7 +64,23 @@ export default function SeriesTabMenu({ tabs }) {
return (
<div id="diagrama-abas" className="scroll-mt-28">
<div role="tablist" aria-label="Placa e diagrama" className="no-scrollbar flex gap-2 overflow-x-auto pb-1">
<div
role="tablist"
aria-label={
effectiveIsZh
? "开发板与图示"
: effectiveIsEn
? "Board and diagram"
: effectiveIsEs
? "Placa y diagrama"
: effectiveIsFr
? "Carte et schéma"
: effectiveIsDe
? "Board und Diagramm"
: "Placa e diagrama"
}
className="no-scrollbar flex gap-2 overflow-x-auto pb-1"
>
{availableTabs.map((tab, indice) => (
<button
key={tab.id}
+385
View File
@@ -0,0 +1,385 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss (Wi-Fi und Bluetooth)"
],
"categorias": [
"Antenne",
"RF"
],
"avisos": [
"Dedizierter HF-Pin. Vermeiden Sie lange Leiterbahnen ohne 50-Ohm-Impedanzanpassung."
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analoge 3.3V-Stromversorgung"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V (3.0V bis 3.6V)",
"Versorgt analoge und HF-Schaltungen des Chips mit Energie"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analoge 3.3V-Stromversorgung"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V (3.0V bis 3.6V)",
"Versorgt analoge und HF-Schaltungen des Chips mit Energie"
]
},
{
"numero": "4",
"nome": "GPIO0",
"tipo": "io",
"funcoes": [
"GPIO0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analoger Eingangspin ADC1 Kanal 0"
]
},
{
"numero": "5",
"nome": "GPIO1",
"tipo": "io",
"funcoes": [
"GPIO1",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analoger Eingangspin ADC1 Kanal 1"
]
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI"
],
"avisos": [
"Beim Flash-Boot standardmäßig auf die Funktion SPI MISO (FSPIQ) gemappt"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Aktiv High. Auf High-Pegel ziehen, um den Chip zu starten.",
"Diesen Pin nicht unbeschaltet (floating) lassen. Für einen stabilen Start externe RC-Verzögerungsschaltung verwenden."
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analoger Eingangspin ADC1 Kanal 3"
]
},
{
"numero": "9",
"nome": "GPIO4",
"tipo": "io",
"funcoes": [
"GPIO4",
"MTMS",
"FSPIQ",
"ADC1_CH4"
],
"categorias": [
"GPIO",
"JTAG",
"SPI",
"ADC"
],
"avisos": [
"Multifunktionspin: JTAG MTMS, SPI2 MISO und ADC1 Kanal 4.",
"Kann zusammen mit anderen JTAG-Pins für JTAG-Debugging verwendet werden."
]
},
{
"numero": "10",
"nome": "GPIO5",
"tipo": "io",
"funcoes": [
"GPIO5",
"MTDI",
"FSPIWP"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunktionspin: JTAG MTDI und SPI2 Write Protect (FSPIWP)."
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"Stromversorgung der RTC-Domäne und Low-Power-E/As"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V"
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"funcoes": [
"GPIO6",
"MTCK",
"FSPICLK"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunktionspin: JTAG MTCK und SPI2-Takt (FSPICLK)."
]
},
{
"numero": "13",
"nome": "GPIO7",
"tipo": "io",
"funcoes": [
"GPIO7",
"MTDO",
"FSPID"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunktionspin: JTAG MTDO und SPI2 MOSI (FSPID)."
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping-Pin für die Boot-Steuerung.",
"Wählt zusammen mit GPIO9 den Boot-Modus des SoCs (muss beim Reset auf 1 liegen für Joint Download Boot, wenn GPIO9=0)."
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Primärer Strapping-Pin. High-Pegel (1) beim Reset aktiviert SPI-Boot (Standard über schwachen Pull-up).",
"Low-Pegel (0) beim Reset versetzt den Chip in den UART/SPI-Download-Modus."
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Multifunktionspin: SPI2 Chip Select 0 (FSPICS0)."
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Digitale Stromversorgung der CPU und zugehörigen E/As (3.3V)"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V"
]
},
{
"numero": "18",
"nome": "GPIO18",
"tipo": "io",
"funcoes": [
"GPIO18"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "19",
"nome": "GPIO19",
"tipo": "io",
"funcoes": [
"GPIO19",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 receive pin (Serial RX by default for flashing and monitoring)."
]
},
{
"numero": "20",
"nome": "GPIO20",
"tipo": "io",
"funcoes": [
"GPIO20",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 transmit pin (Serial TX by default for flashing and monitoring)."
]
},
{
"numero": "21",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Analoge 3.3V-Eingangsversorgung"
],
"categorias": [
"Power"
],
"avisos": []
},
{
"numero": "22",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Externer Quarzoszillator-Anschluss (Ausgang)"
],
"categorias": [
"Clock"
],
"avisos": []
},
{
"numero": "23",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Externer Quarzoszillator-Anschluss (Eingang)"
],
"categorias": [
"Clock"
],
"avisos": []
},
{
"numero": "24",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Analoge 3.3V-Eingangsversorgung"
],
"categorias": [
"Power"
],
"avisos": []
},
{
"numero": "25",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Zentraler Massepunkt (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Muss für stabile Leistung und Entwärmung ordnungsgemäß mit der Massefläche (GND) der Leiterplatte verlötet werden."
]
}
]
+574
View File
@@ -0,0 +1,574 @@
[
{
"numero": "1",
"nome": "LNA_IN",
"tipo": "analog",
"funcoes": [
"Ein- und Ausgang für HF-Signale (Wi-Fi und Bluetooth) zur Antenne"
],
"categorias": [
"Antenne"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "3",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "4",
"nome": "XTAL_32K_P",
"tipo": "io",
"funcoes": [
"GPIO0",
"XTAL_32K_P",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
],
"avisos": []
},
{
"numero": "5",
"nome": "XTAL_32K_N",
"tipo": "io",
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
],
"avisos": []
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"This pin does not set boot mode, but connecting it with a pull-up is recommended to prevent glitches (see datasheet section 3.1)"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung"
],
"categorias": [
"Power"
],
"avisos": [
"Ein High-Pegel an diesem Pin aktiviert den Betrieb des Chips",
"Ein Low-Pegel an diesem Pin deaktiviert den Betrieb des Chips",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "9",
"nome": "MTMS",
"tipo": "io",
"funcoes": [
"GPIO4",
"ADC1_CH4",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "10",
"nome": "MTDI",
"tipo": "io",
"funcoes": [
"GPIO5",
"ADC2_CH0",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"Versorgungseingang der Low-Power-Domäne und Teilen der digitalen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"funcoes": [
"GPIO6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"funcoes": [
"GPIO7",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "18",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Versorgungsein-/ausgang für internen/externen Flash-Speicher",
"GPIO11"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts",
"Kann nur als GPIO genutzt werden, wenn der Flash-Speicher über eine externe Quelle versorgt wird"
]
},
{
"numero": "19",
"nome": "SPIHD",
"tipo": "io",
"funcoes": [
"GPIO12",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "20",
"nome": "SPIWP",
"tipo": "io",
"funcoes": [
"GPIO13",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "21",
"nome": "SPICS0",
"tipo": "io",
"funcoes": [
"GPIO14",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "22",
"nome": "SPICLK",
"tipo": "io",
"funcoes": [
"GPIO15",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "23",
"nome": "SPID",
"tipo": "io",
"funcoes": [
"GPIO16",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "24",
"nome": "SPIQ",
"tipo": "io",
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "25",
"nome": "GPIO18",
"tipo": "io",
"funcoes": [
"GPIO18",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "26",
"nome": "GPIO19",
"tipo": "io",
"funcoes": [
"GPIO19",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "27",
"nome": "U0RXD",
"tipo": "io",
"funcoes": [
"GPIO20",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "28",
"nome": "U0TXD",
"tipo": "io",
"funcoes": [
"GPIO21",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Nach dem Reset ist an diesem Pin der interne Pull-up aktiviert",
"Pin für Debugging genutzt"
]
},
{
"numero": "29",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negativer Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.2 des Datenblatts"
]
},
{
"numero": "30",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positiver Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.2 des Datenblatts"
]
},
{
"numero": "31",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "32",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
}
]
+862
View File
@@ -0,0 +1,862 @@
[
{
"numero": "1",
"nome": "VDDA6",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "2",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
},
{
"numero": "3",
"nome": "VDDA7",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "4",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negativer Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.3 des Datenblatts"
]
},
{
"numero": "5",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positiver Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.3 des Datenblatts"
]
},
{
"numero": "6",
"nome": "VDDA8",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "7",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung"
],
"categorias": [
"Power"
],
"avisos": [
"Ein High-Pegel an diesem Pin aktiviert den Betrieb des Chips",
"Ein Low-Pegel an diesem Pin deaktiviert den Betrieb des Chips",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "8",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen Low-Power-Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "9",
"nome": "XTAL_32K_P",
"tipo": "io",
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
],
"avisos": []
},
{
"numero": "10",
"nome": "XTAL_32K_N",
"tipo": "io",
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
],
"avisos": []
},
{
"numero": "11",
"nome": "MTMS",
"tipo": "io",
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"LP_I2C_SDA",
"ADC1_CH1",
"FSPIQ",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"SPI",
"JTAG",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Die I2C_SDA-Funktion ist im Low-Power-Modus (LP) verfügbar",
"Pin für Debugging genutzt",
"Steuert die Frequenz des Quarzoszillators (siehe Abschnitt 3.5 des Datenblatts für Details)"
]
},
{
"numero": "12",
"nome": "MTDI",
"tipo": "io",
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"LP_I2C_SCL",
"ADC1_CH2",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"JTAG",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Die I2C_SDA-Funktion ist im Low-Power-Modus (LP) verfügbar",
"Pin für Debugging genutzt",
"Steuert das Timing des SDIO-Slave (siehe Abschnitt 3.2 des Datenblatts für Details)"
]
},
{
"numero": "13",
"nome": "MTCK",
"tipo": "io",
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "14",
"nome": "MTDO",
"tipo": "io",
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH4",
"FSPIWP",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "15",
"nome": "GPIO6",
"tipo": "io",
"funcoes": [
"GPIO6",
"LP_GDIO6",
"ADC1_CH5",
"FSPICLK"
],
"categorias": [
"GPIO",
"Low Power",
"ADC",
"SPI"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "16",
"nome": "GPIO7",
"tipo": "io",
"funcoes": [
"GPIO7",
"FSPID",
"SDIO_DATA1"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert die Quelle der JTAG-Signale (siehe Abschnitt 3.4 des Datenblatts für Details)"
]
},
{
"numero": "17",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8",
"SDIO_DATA0",
"PAD_COMP0"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "18",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9",
"SDIO_CLK",
"PAD_COMP1"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "19",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10",
"FSPICS0",
"SDIO_CMD"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "20",
"nome": "U0TXD",
"tipo": "io",
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Nach dem Reset ist an diesem Pin der interne Pull-up aktiviert",
"Pin für Debugging genutzt"
]
},
{
"numero": "21",
"nome": "U0RXD",
"tipo": "io",
"funcoes": [
"GPIO12",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "22",
"nome": "GPIO13",
"tipo": "io",
"funcoes": [
"GPIO13",
"USB_D-",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "23",
"nome": "GPIO14",
"tipo": "io",
"funcoes": [
"GPIO14",
"USB_D+",
"SDIO_DATA4"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"Während des Resets ist der interne USB-Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen USB-Pull-up konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "24",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen High-Performance-Domäne und Teilen der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "25",
"nome": "SPICS1",
"tipo": "io",
"funcoes": [
"GPIO15",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "26",
"nome": "SPICS0",
"tipo": "io",
"funcoes": [
"GPIO16",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "27",
"nome": "SPIQ",
"tipo": "io",
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "28",
"nome": "SPIWP",
"tipo": "io",
"funcoes": [
"GPIO18",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "29",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Versorgungsausgang für externen Flash",
"GPIO19"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts",
"Kann nur als GPIO genutzt werden, wenn der externe Flash-Speicher über eine externe Quelle versorgt wird"
]
},
{
"numero": "30",
"nome": "SPIHD",
"tipo": "io",
"funcoes": [
"GPIO20",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "31",
"nome": "SPICLK",
"tipo": "io",
"funcoes": [
"GPIO21",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "32",
"nome": "SPID",
"tipo": "io",
"funcoes": [
"GPIO22",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "33",
"nome": "GPIO23",
"tipo": "io",
"funcoes": [
"GPIO23"
],
"categorias": [
"GPIO"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "34",
"nome": "GPIO24",
"tipo": "io",
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "35",
"nome": "GPIO25",
"tipo": "io",
"funcoes": [
"GPIO25"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert das Timing des SDIO-Slave (siehe Abschnitt 3.4 des Datenblatts für Details)"
]
},
{
"numero": "36",
"nome": "GPIO26",
"tipo": "io",
"funcoes": [
"GPIO26"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "37",
"nome": "GPIO27",
"tipo": "io",
"funcoes": [
"GPIO27"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)",
"Steuert die Ausgabe von ROM-Meldungen auf UART0 (siehe Abschnitt 3.3 des Datenblatts für Details)"
]
},
{
"numero": "38",
"nome": "GPIO28",
"tipo": "io",
"funcoes": [
"GPIO28"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "39",
"nome": "VDDPST3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen High-Performance-Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "40",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "41",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "42",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss für 2-GHz-Band"
],
"categorias": [
"Antenne"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "43",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
},
{
"numero": "44",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "44",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "45",
"nome": "VDDA5",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "47",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
},
{
"numero": "48",
"nome": "ANT_5G",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss für 5-GHz-Band"
],
"categorias": [
"Antenne"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
}
]
+757
View File
@@ -0,0 +1,757 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss"
],
"categorias": [
"Antenne"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung"
],
"categorias": [
"Power"
],
"avisos": [
"Ein High-Pegel an diesem Pin aktiviert den Betrieb des Chips",
"Ein Low-Pegel an diesem Pin deaktiviert den Betrieb des Chips",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen Low-Power-Domäne und Teilen der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "6",
"nome": "XTAL_32K_P",
"tipo": "io",
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
],
"avisos": []
},
{
"numero": "7",
"nome": "XTAL_32K_N",
"tipo": "io",
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
],
"avisos": []
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "10",
"nome": "MTMS",
"tipo": "io",
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt",
"Steuert das Timing des SDIO-Slave (siehe Abschnitt 3.2 des Datenblatts für Details)"
]
},
{
"numero": "11",
"nome": "MTDI",
"tipo": "io",
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH5",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt",
"Steuert das Timing des SDIO-Slave (siehe Abschnitt 3.2 des Datenblatts für Details)"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"funcoes": [
"GPIO6",
"LP_GDIO6",
"LP_I2C_SDA",
"ADC1_CH6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Die I2C_SDA-Funktion ist im Low-Power-Modus (LP) verfügbar",
"Pin für Debugging genutzt"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"funcoes": [
"GPIO7",
"LP_GDIO7",
"LP_I2C_SCL",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"SPI",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Die I2C_SDA-Funktion ist im Low-Power-Modus (LP) verfügbar",
"Pin für Debugging genutzt"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)",
"Steuert die Ausgabe von ROM-Meldungen auf UART0 (siehe Abschnitt 3.3 des Datenblatts für Details)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10"
],
"categorias": [
"GPIO"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "17",
"nome": "GPIO11",
"tipo": "io",
"funcoes": [
"GPIO11"
],
"categorias": [
"GPIO"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "18",
"nome": "GPIO12",
"tipo": "io",
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "19",
"nome": "GPIO13",
"tipo": "io",
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "20",
"nome": "SPICS0",
"tipo": "io",
"funcoes": [
"GPIO24",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "21",
"nome": "SPIQ",
"tipo": "io",
"funcoes": [
"GPIO25",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "22",
"nome": "SPIWP",
"tipo": "io",
"funcoes": [
"GPIO26",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "23",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Versorgungsein-/ausgang für Flash-Speicher",
"GPIO27"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts",
"Kann nur als GPIO genutzt werden, wenn der externe Flash-Speicher über eine externe Quelle versorgt wird"
]
},
{
"numero": "24",
"nome": "SPIHD",
"tipo": "io",
"funcoes": [
"GPIO28",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "25",
"nome": "SPICLK",
"tipo": "io",
"funcoes": [
"GPIO29",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "26",
"nome": "SPID",
"tipo": "io",
"funcoes": [
"GPIO30",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Vom SPI-Flash-Speicher belegt",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "27",
"nome": "GPIO15",
"tipo": "io",
"funcoes": [
"GPIO15"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert die Quelle der JTAG-Signale (siehe Abschnitt 3.4 des Datenblatts für Details)"
]
},
{
"numero": "28",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Versorgungseingang der digitalen High-Performance-Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "29",
"nome": "U0TXD",
"tipo": "io",
"funcoes": [
"GPIO16",
"U0TXD",
"FSPICS0"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Nach dem Reset ist an diesem Pin der interne Pull-up aktiviert",
"Pin für Debugging genutzt"
]
},
{
"numero": "30",
"nome": "U0RXD",
"tipo": "io",
"funcoes": [
"GPIO17",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "31",
"nome": "SDIO_CMD",
"tipo": "io",
"funcoes": [
"GPIO18",
"SDIO_CMD",
"FSPICS2"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "32",
"nome": "SDIO_CLK",
"tipo": "io",
"funcoes": [
"GPIO19",
"SDIO_CLK",
"FSPICS3"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "33",
"nome": "SDIO_DATA0",
"tipo": "io",
"funcoes": [
"GPIO20",
"SDIO_DATA0",
"FSPICS4"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "34",
"nome": "SDIO_DATA1",
"tipo": "io",
"funcoes": [
"GPIO21",
"SDIO_DATA1",
"FSPICS5"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "35",
"nome": "SDIO_DATA2",
"tipo": "io",
"funcoes": [
"GPIO22",
"SDIO_DATA2"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "36",
"nome": "SDIO_DATA3",
"tipo": "io",
"funcoes": [
"GPIO23",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Während des Resets ist der interne Pull-up aktiviert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert"
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negativer Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positiver Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "41",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
}
]
+642
View File
@@ -0,0 +1,642 @@
[
{
"numero": "1",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss (Wi-Fi und Bluetooth)"
],
"categorias": [
"Antenne",
"RF"
],
"avisos": [
"Dedicated 2.4 GHz RF pin. Requires 50-ohm impedance matching."
]
},
{
"numero": "2",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"Stromversorgung der analogen Domäne (3.3V)"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V (3.0V bis 3.6V). Versorgt HF- und Taktschaltungen mit Energie."
]
},
{
"numero": "3",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"Stromversorgung der analogen Domäne (3.3V)"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V (3.0V bis 3.6V). Versorgt HF- und Taktschaltungen mit Energie."
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Aktiv High. Auf High-Pegel ziehen, um den Chip zu starten.",
"Do not leave this pin floating. An external RC circuit is recommended for clean reset."
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Digitale Stromversorgung der HP- und LP-Domänen (High Performance / Low Power)"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V. Versorgt den digitalen Low-Power-Bereich und zugehörige Pins."
]
},
{
"numero": "6",
"nome": "GPIO0",
"tipo": "io",
"funcoes": [
"GPIO0",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
],
"avisos": [
"Low-power multifunction pin. Can connect to external 32 kHz crystal (Input P)."
]
},
{
"numero": "7",
"nome": "GPIO1",
"tipo": "io",
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
],
"avisos": [
"Multifunction pin. External 32 kHz crystal connection (Output N) and ADC1 Channel 0 analog input."
]
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"funcoes": [
"GPIO2"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"funcoes": [
"GPIO3",
"MTMS",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Multifunktionspin: JTAG MTMS, ADC1 Kanal 1 und Strapping-Pin für SDIO-Taktflankensteuerung.",
"Floating by default during reset."
]
},
{
"numero": "10",
"nome": "GPIO4",
"tipo": "io",
"funcoes": [
"GPIO4",
"MTDI",
"ADC1_CH2"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Multifunktionspin: JTAG MTDI, ADC1 Kanal 2 und Strapping-Pin für SDIO-Taktflankensteuerung.",
"Floating by default during reset."
]
},
{
"numero": "11",
"nome": "GPIO5",
"tipo": "io",
"funcoes": [
"GPIO5",
"MTCK",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"JTAG",
"ADC"
],
"avisos": [
"Multifunction pin: JTAG MTCK and ADC1 Channel 3 analog input."
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"funcoes": [
"GPIO6",
"MTDO"
],
"categorias": [
"GPIO",
"JTAG"
],
"avisos": [
"Multifunction pin: JTAG MTDO."
]
},
{
"numero": "13",
"nome": "GPIO25",
"tipo": "io",
"funcoes": [
"GPIO25",
"SDIO_CMD",
"FSPICS0"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Command or SPI2 Chip Select 0."
]
},
{
"numero": "14",
"nome": "GPIO26",
"tipo": "io",
"funcoes": [
"GPIO26",
"SDIO_CLK",
"FSPICLK"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Clock or SPI2 Clock."
]
},
{
"numero": "15",
"nome": "GPIO27",
"tipo": "io",
"funcoes": [
"GPIO27",
"SDIO_DATA0",
"FSPID"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Data 0 or SPI2 MOSI (FSPID)."
]
},
{
"numero": "16",
"nome": "GPIO28",
"tipo": "io",
"funcoes": [
"GPIO28",
"SDIO_DATA1",
"FSPIQ"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 1 or SPI2 MISO (FSPIQ)."
]
},
{
"numero": "17",
"nome": "GPIO22",
"tipo": "io",
"funcoes": [
"GPIO22",
"SDIO_DATA2",
"FSPIWP"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 2 or SPI2 Write Protect."
]
},
{
"numero": "18",
"nome": "GPIO23",
"tipo": "io",
"funcoes": [
"GPIO23",
"SDIO_DATA3",
"FSPIHD"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 3 or SPI2 Hold."
]
},
{
"numero": "19",
"nome": "GPIO14",
"tipo": "io",
"funcoes": [
"GPIO14",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Dedicated Chip Select 1 pin for SPI Flash/PSRAM memory interface."
]
},
{
"numero": "20",
"nome": "GPIO15",
"tipo": "io",
"funcoes": [
"GPIO15",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Dedicated Chip Select 0 pin for SPI Flash memory interface."
]
},
{
"numero": "21",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"Stromversorgung der digitalen HP-Domäne (High Performance)"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V (3.0V bis 3.6V). Versorgt die schnellen digitalen Schnittstellen."
]
},
{
"numero": "22",
"nome": "GPIO16",
"tipo": "io",
"funcoes": [
"GPIO16",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Data Q (MISO) pin for SPI flash memory interface."
]
},
{
"numero": "23",
"nome": "GPIO17",
"tipo": "io",
"funcoes": [
"GPIO17",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Write Protect pin for SPI flash memory interface."
]
},
{
"numero": "24",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Aus VDDPST2 generierte LDO-Ausgangsspannung zur Speisung von Flash und PSRAM"
],
"categorias": [
"Power"
],
"avisos": [
"Ausgangsspannung per Software konfigurierbar gemäß Flash-Spezifikation (üblicherweise 3.3V oder 1.8V).",
"Must not be used as a general high-current power source."
]
},
{
"numero": "25",
"nome": "GPIO19",
"tipo": "io",
"funcoes": [
"GPIO19",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Hold control pin for SPI flash memory interface."
]
},
{
"numero": "26",
"nome": "GPIO20",
"tipo": "io",
"funcoes": [
"GPIO20",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Clock signal pin for SPI flash memory interface."
]
},
{
"numero": "27",
"nome": "GPIO21",
"tipo": "io",
"funcoes": [
"GPIO21",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Data D (MOSI) pin for SPI flash memory interface."
]
},
{
"numero": "28",
"nome": "GPIO12",
"tipo": "io",
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Negative signal pin of integrated USB Serial/JTAG transceiver."
]
},
{
"numero": "29",
"nome": "GPIO13",
"tipo": "io",
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Positive signal pin of integrated USB Serial/JTAG transceiver.",
"Verfügt über integrierten Pull-up-Widerstand, der beim USB-Start standardmäßig aktiv ist."
]
},
{
"numero": "30",
"nome": "GPIO24",
"tipo": "io",
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "31",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping pin for boot mode selection and ROM log printing control.",
"Floating by default during reset. High level (1) enables boot log printing."
]
},
{
"numero": "32",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Primary Strapping pin for boot mode selection.",
"Mit integriertem schwachen Pull-up ausgestattet. High-Pegel (1) beim Reset aktiviert SPI-Boot (Flash). Low-Pegel (0) erzwingt den Download-Modus."
]
},
{
"numero": "33",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Serieller Empfang UART0 (Serial RX für externes Flashen und Debugging)."
]
},
{
"numero": "34",
"nome": "GPIO11",
"tipo": "io",
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Serielle Übertragung UART0 (Serial TX für externes Flashen und Debugging)."
]
},
{
"numero": "35",
"nome": "GPIO29",
"tipo": "io",
"funcoes": [
"GPIO29"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "36",
"nome": "GPIO7",
"tipo": "io",
"funcoes": [
"GPIO7"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping pin for JTAG signal source selection (early boot).",
"Keine internen Pull-Widerstände beim Reset. Muss bei Verwendung extern stabil gehalten werden."
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Stromversorgung der analogen Domäne (3.3V)"
],
"categorias": [
"Power"
],
"avisos": []
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Externer 40-MHz-Quarzoszillator-Anschluss (Ausgang N)"
],
"categorias": [
"Clock"
],
"avisos": []
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Externer 40-MHz-Quarzoszillator-Anschluss (Eingang P)"
],
"categorias": [
"Clock"
],
"avisos": []
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Stromversorgung der analogen Domäne (3.3V)"
],
"categorias": [
"Power"
],
"avisos": []
},
{
"numero": "41",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Zentraler Massepunkt (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Muss für stabilen HF- und thermischen Betrieb ordnungsgemäß mit der Massefläche (GND) der Leiterplatte verlötet werden."
]
}
]
+549
View File
@@ -0,0 +1,549 @@
[
{
"numero": "1",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "3",
"nome": "GPIO0",
"tipo": "io",
"funcoes": [
"GPIO0",
"FSPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": []
},
{
"numero": "4",
"nome": "GPIO1",
"tipo": "io",
"funcoes": [
"GPIO1",
"FSPICS0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"SPI",
"ADC"
],
"avisos": []
},
{
"numero": "5",
"nome": "MTMS",
"tipo": "io",
"funcoes": [
"GPIO1",
"FSPIWP",
"ADC1_CH1",
"MTMS"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "6",
"nome": "MTDO",
"tipo": "io",
"funcoes": [
"GPIO3",
"FSPIHD",
"ADC1_CH2",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "7",
"nome": "MTCK",
"tipo": "io",
"funcoes": [
"GPIO4",
"FSPICLK",
"ADC1_CH3",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "8",
"nome": "MTDI",
"tipo": "io",
"funcoes": [
"GPIO5",
"FSPID",
"ADC1_CH4",
"MTDI"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "9",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der E/A-Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "10",
"nome": "GPIO8",
"tipo": "io",
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)",
"Steuert die Ausgabe von ROM-Meldungen auf UART0 (siehe Abschnitt 3.3 des Datenblatts für Details)"
]
},
{
"numero": "11",
"nome": "GPIO9",
"tipo": "io",
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Steuert den Boot-Modus des Chips (siehe Abschnitt 3.1 des Datenblatts für Details)"
]
},
{
"numero": "12",
"nome": "GPIO10",
"tipo": "io",
"funcoes": [
"GPIO10",
"ZCD0"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "13",
"nome": "GPIO11",
"tipo": "io",
"funcoes": [
"GPIO11",
"ZCD1"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "14",
"nome": "GPIO12",
"tipo": "io",
"funcoes": [
"GPIO12"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "15",
"nome": "XTAL_32K_P",
"tipo": "io",
"funcoes": [
"GPIO13",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
],
"avisos": []
},
{
"numero": "16",
"nome": "XTAL_32K_N",
"tipo": "io",
"funcoes": [
"GPIO14",
"XTAL_32K_N"
],
"categorias": [
"GPIO",
"Clock"
],
"avisos": []
},
{
"numero": "17",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Chip-Aktivierung"
],
"categorias": [
"Power"
],
"avisos": [
"Ein High-Pegel an diesem Pin aktiviert den Betrieb des Chips",
"Ein Low-Pegel an diesem Pin deaktiviert den Betrieb des Chips",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "18",
"nome": "VBAT",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne oder Batterie"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "19",
"nome": "VDDA_PMU",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "20",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Versorgungseingang der E/A-Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "21",
"nome": "GPIO22",
"tipo": "io",
"funcoes": [
"GPIO22"
],
"categorias": [
"GPIO"
],
"avisos": []
},
{
"numero": "22",
"nome": "U0RXD",
"tipo": "io",
"funcoes": [
"GPIO23",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "23",
"nome": "U0TXD",
"tipo": "io",
"funcoes": [
"GPIO24",
"U0TXD",
"FSPICS2"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen Pull-up konfiguriert",
"Pin für Debugging genutzt"
]
},
{
"numero": "24",
"nome": "GPIO25",
"tipo": "io",
"funcoes": [
"GPIO24",
"FSPICS3"
],
"categorias": [
"GPIO",
"SPI",
"Strapping"
],
"avisos": [
"Während des Resets ist dieser Pin als Eingang konfiguriert",
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Steuert die Quelle der JTAG-Signale (siehe Abschnitt 3.3 des Datenblatts für Details)"
]
},
{
"numero": "25",
"nome": "GPIO26",
"tipo": "io",
"funcoes": [
"GPIO26",
"FSPICS4",
"USB_D-"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "26",
"nome": "GPIO27",
"tipo": "io",
"funcoes": [
"GPIO27",
"FSPICS5",
"USB_D+"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"Nach dem Reset ist dieser Pin als Eingang mit aktivem internen USB-Pull-up konfiguriert",
"Standardmäßig wird dieser Pin für USB Serial/JTAG genutzt"
]
},
{
"numero": "27",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "28",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negativer Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.2 des Datenblatts"
]
},
{
"numero": "29",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positiver Taktein-/ausgang"
],
"categorias": [
"Clock"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.3.2 des Datenblatts"
]
},
{
"numero": "30",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "31",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Versorgungseingang der analogen Domäne"
],
"categorias": [
"Power"
],
"avisos": [
"Empfohlene Spannung: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"Weitere Details zur Stromversorgung des Chips finden Sie in Abschnitt 2.5 des Datenblatts"
]
},
{
"numero": "32",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"HF-Antennenanschluss"
],
"categorias": [
"Antenne"
],
"avisos": [
"Weitere Details zu analogen Pins finden Sie in Abschnitt 2.4 des Datenblatts"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Elektrische Schaltungsmasse (GND)"
],
"categorias": [
"GND"
],
"avisos": []
}
]
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+423
View File
@@ -0,0 +1,423 @@
{
"ESP-IDF": {
"nome": "ESP-IDF",
"icone": "⚙️",
"nome_completo": "Espressif IoT Development Framework",
"descricao": "Offizielles natives Framework von Espressif für alle ESP32-SoCs. Basiert auf Multicore-FreeRTOS und CMake und bietet die vollständige Kontrolle über Silizium, Peripheriegeräte, Funk sowie eine modulare Komponentenarchitektur.",
"linguagem": "C / C++",
"tipo": "Offizielles Basis-Framework",
"funcao_principal": "Industrielle und hochperformante Entwicklung mit direktem Registerzugriff, Echtzeit-RTOS und vollständigem Protokoll-Stack",
"caracteristicas": [
"Echtzeitbetriebssystem (FreeRTOS SMP Multicore)",
"Nativer Support für ESP Component Registry über idf_component.yml",
"Vollständiger Konnektivitäts-Stack für Wi-Fi 4/6, BLE 5.x, Zigbee und Thread",
"Unterstützung aller SoCs (ESP32, S2, S3, C2, C3, C6, H2, P4)",
"Erweitertes Energiemanagement und Deep-Sleep-Modi",
"Robuste Sicherheit: Secure Boot v2, Flash-Verschlüsselung und Hardware-Kryptografie",
"Verschlüsselte OTA-Updates mit automatischem Rollback",
"Moderne Clang/GCC-Toolchain, C++23-Unterstützung und JTAG-OpenOCD-Debugging"
],
"casos_uso": [
"Kommerzielle und industrielle IoT-Produkte",
"Geräte mit strengen Batterie- und Low-Power-Anforderungen",
"Echtzeitanwendungen mit präziser Interrupt-Steuerung",
"Sicherheitssysteme mit Hardware-Verschlüsselung",
"Leistungsstarke Multiprotokoll-Gateways"
],
"exemplo": "/exemplos/esp-idf.c",
"exemplos": "https://github.com/espressif/esp-idf/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-idf/en/latest/",
"repositorio": "https://github.com/espressif/esp-idf",
"cor": "#E74C3C"
},
"ESP-RainMaker": {
"nome": "ESP-RainMaker",
"icone": "☁️",
"nome_completo": "ESP RainMaker AIoT Cloud Platform",
"descricao": "Komplette Cloud- und Firmware-Plattform von Espressif für vernetzte Produkte. Ermöglicht die Entwicklung von IoT-Geräten ohne eigenen Backend- oder App-Aufbau von Grund auf.",
"linguagem": "C / C++",
"tipo": "Cloud & AIoT Framework",
"funcao_principal": "Beschleunigte Entwicklung intelligenter Produkte mit mobilen Apps (iOS/Android), AWS-Serverless-Cloud und Sprachsteuerung (Alexa/Google Home)",
"caracteristicas": [
"Assistiere Wi-Fi- und BLE-Bereitstellung über die offizielle mobile App",
"Dynamische Generierung der Benutzeroberfläche in der App basierend auf Firmware-Parametern",
"Native Integration mit Alexa und Google Assistant",
"Gleichzeitige lokale Steuerung (über mDNS/HTTP) und Cloud-Steuerung",
"RainMaker-Dashboard für Flottenmanagement und OTA-Aktualisierungen",
"Native Kompatibilität mit Matter-Knoten und Geräte-Bridges",
"Integrierte Bibliothek über ESP Component Registry (espressif/esp_rainmaker)"
],
"casos_uso": [
"Smarte Haushaltsgeräte und vernetzte weiße Ware",
"Intelligente Beleuchtung und Steckdosen für Endverbraucher",
"Klimasysteme (HVAC) und vernetzte Thermostate",
"Kommerzielle IoT-Prototypen mit schneller Marktvalidierung",
"Produkte mit Zertifizierungsanforderungen für Apple Home, Alexa und Google Home"
],
"exemplo": "/exemplos/esp-rainmaker.c",
"exemplos": "https://github.com/espressif/esp-rainmaker/tree/master/examples",
"documentacao": "https://rainmaker.espressif.com/docs/get-started.html",
"repositorio": "https://github.com/espressif/esp-rainmaker",
"cor": "#2980B9"
},
"ESP-Matter": {
"nome": "ESP-Matter",
"icone": "🏠",
"nome_completo": "ESP-Matter SDK",
"descricao": "Offizielles SDK von Espressif für den universellen Matter-Standard (CSA). Bietet direkte Interoperabilität mit Apple Home, Google Home, Alexa und SmartThings.",
"linguagem": "C / C++",
"tipo": "Smart Home Framework",
"funcao_principal": "Entwicklung einheitlicher, interoperabler Smart-Home-Geräte über Wi-Fi oder Thread (OpenThread)",
"caracteristicas": [
"Standardkonforme Implementierung von Connected Home over IP (Project CHIP / CSA)",
"Unterstützung für Matter over Wi-Fi (ESP32, S3, C3, C6) und Matter over Thread (ESP32-H2, C6)",
"Unterstützung für Endgeräte-Rollen (Device), Controller und Bridges (Matter Bridge)",
"Sichere universelle Kopplung mit DAC-Zertifikaten (Device Attestation Certificate)",
"Nahtlose Integration mit ESP-IDF und ESP-RainMaker",
"Standard-Cluster-Unterstützung: Ein/Aus, Dimmer, Sensoren, Thermostate",
"Synchronisation mit Apple-, Google-, Alexa- und SmartThings-Ökosystemen ohne herstellerspezifisches Gateway"
],
"casos_uso": [
"Matter-zertifizierte Smart-Home-Geräte (Lampen, Steckdosen, Schlösser)",
"Bridges von Zigbee/BLE zu Matter (Matter Bridges)",
"Energiesparende Umgebungssensoren in Thread-Netzwerken (ESP32-H2)",
"Universelle Wandtaster und Aktoren",
"Ökosystem-übergreifende Geräte ohne proprietäre App-Pflicht"
],
"exemplo": "/exemplos/esp-matter.c",
"exemplos": "https://github.com/espressif/esp-matter/tree/main/examples",
"documentacao": "https://docs.espressif.com/projects/esp-matter/en/latest/",
"repositorio": "https://github.com/espressif/esp-matter",
"cor": "#16A085"
},
"ESP-ADF": {
"nome": "ESP-ADF",
"icone": "🎵",
"nome_completo": "ESP Audio Development Framework",
"descricao": "Offizielles Framework für Audioanwendungen auf ESP32-SoCs. Enthält Pipelines für Decodierung/Codierung, Treiber für I2S-Codecs und Netzwerk-Audiostreaming.",
"linguagem": "C / C++",
"tipo": "Audio Processing Framework",
"funcao_principal": "Audioverarbeitung, Erfassung, Wiedergabe und Streaming auf eingebetteten Systemen mit Hardware- und Software-Codecs",
"caracteristicas": [
"Elementbasierte Pipeline-Architektur (Audio Pipeline Framework)",
"Decodierung und Codierung: MP3, AAC, WAV, OGG, FLAC, OPUS und AMR",
"Integrierte Treiber für gängige I2S-Codecs (ES8388, ES8311, TAS5805M, AC101)",
"Streaming-Protokolle: HTTP Live Streaming (HLS), DLNA, SIP und Webradio",
"Integration mit ESP-SR für lokale Sprachsteuerung und akustische Echounterdrückung (AEC)",
"Lautstärkeregelung, grafischer Equalizer (EQ) und Mehrkanal-Audiomixer",
"Unterstützung für Bluetooth-Audioprofile: A2DP Sink, A2DP Source und BLE Audio"
],
"casos_uso": [
"Smarte Lautsprecher und Bluetooth-/Wi-Fi-Audioempfänger",
"Zweiwege-Gegensprechanlagen (VoIP / SIP)",
"Intelligente Türklingeln mit Audioerfassung und -übertragung",
"Netzwerk-Audioplayer für Online-Radio und Podcasts",
"Alarmsysteme und industrielle akustische Rückmeldungen"
],
"exemplo": "/exemplos/esp-adf.c",
"exemplos": "https://github.com/espressif/esp-adf/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-adf/en/latest/",
"repositorio": "https://github.com/espressif/esp-adf",
"cor": "#9B59B6"
},
"ESP-SR": {
"nome": "ESP-SR",
"icone": "🎙️",
"nome_completo": "ESP Speech Recognition Framework",
"descricao": "Framework von Espressif für Spracherkennung und lokale Audioverarbeitung (On-Device) ohne Internetverbindung – mit minimaler Latenz und vollem Datenschutz.",
"linguagem": "C / C++",
"tipo": "AI & Speech Framework",
"funcao_principal": "On-Chip-Spracherkennung: Wake-Word-Erkennung (WakeNet) und lokale Offline-Befehle (MultiNet)",
"caracteristicas": [
"WakeNet-Aktivierungsworterkennung (z. B. 'Hi ESP', 'Hi Lexin') mit hoher Präzision",
"Erkennung lokaler MultiNet-Befehle mit mehrsprachiger Unterstützung",
"Akustisches Front-End (AFE): akustische Echounterdrückung (AEC)",
"Hintergrundgeräuschunterdrückung (BSS/NS) und Richtmikrofonie (Beamforming)",
"Automatische Verstärkungsregelung (AGC) und Sprachaktivitätserkennung (VAD)",
"Vektorbeschleunigung auf ESP32-S3 (Xtensa-SIMD-Instruktionen)",
"Vollständiger Offline-Betrieb ohne Datenübertragung an Cloud-Dienste"
],
"casos_uso": [
"Wandbedienfelder für die Gebäudeautomation mit Sprachsteuerung",
"Sprachgesteuerte Haushaltsgeräte ohne Internetabhängigkeit",
"Industriegeräte mit freihändiger Bedienung",
"Interaktives Spielzeug und Lernsysteme",
"Sprachschnittstellen mit strikten Datenschutzanforderungen"
],
"exemplo": "/exemplos/esp-sr.c",
"exemplos": "https://github.com/espressif/esp-sr/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-sr/en/latest/",
"repositorio": "https://github.com/espressif/esp-sr",
"cor": "#3498DB"
},
"ESP-IoT-Solution": {
"nome": "ESP-IoT-Solution",
"icone": "🧰",
"nome_completo": "ESP-IoT-Solution Component Library",
"descricao": "Offizielle Sammlung von Peripherietreibern, Touch-Algorithmen, Energieverwaltungsfunktionen und IoT-Dienstprogrammen zur Beschleunigung der Entwicklung auf ESP-IDF.",
"linguagem": "C / C++",
"tipo": "Drivers & IoT Utilities",
"funcao_principal": "Einsatzbereite Bibliothek für Sensortreiber, Displays, Industriebusse und kapazitive Berührungssensorik",
"caracteristicas": [
"Fertige Treiber für Sensoren (I2C, SPI): Temperatur, Druck, IMU, Licht",
"Treiber für OLED- und LCD-Displays (SSD1306, ST7789, ILI9341, GC9A01)",
"Erweiterte Tastenverwaltung (Klick, Doppelklick, langes Drücken) und Drehimpulsgeber",
"Kapazitive Berührungsalgorithmen: Tasten, Schieberegler, Räder und Näherungserkennung",
"E/A-Expander-Treiber (PCA9557, MCP23017, CH422G)",
"Komponenten für Industriebusse: Modbus RTU/TCP und RS485-Kommunikation",
"Direkte Einbindung als ESP-IDF-Komponenten über idf_component.yml"
],
"casos_uso": [
"Kapazitive Touch-Oberflächen für Haushaltsgeräte und Wandtaster",
"Wetterstationen und Umweltmonitore mit I2C-Sensoren",
"Industrielle Automatisierungsgeräte mit RS485- und Modbus-Kommunikation",
"Projekte mit Grafikdisplays und Drehreglern",
"Systeme mit komplexen Tastenkombinationen und Benutzerereignissen"
],
"exemplo": "/exemplos/esp-iot-solution.c",
"exemplos": "https://github.com/espressif/esp-iot-solution/tree/usb/examples",
"documentacao": "https://docs.espressif.com/projects/esp-iot-solution/en/latest/",
"repositorio": "https://github.com/espressif/esp-iot-solution",
"cor": "#F39C12"
},
"ESP-NOW": {
"nome": "ESP-NOW",
"icone": "⚡",
"nome_completo": "ESP-NOW Wireless Communication Protocol",
"descricao": "Proprietäres Drahtlosprotokoll von Espressif basierend auf 802.11-Aktionsframes. Ermöglicht schnelle, energiesparende Punkt-zu-Punkt-Kommunikation ohne Wi-Fi-Router.",
"linguagem": "C / C++",
"tipo": "Fast Wireless Protocol",
"funcao_principal": "Ultraschnelle, energiesparende Funkkommunikation zwischen ESP-Geräten ohne Wi-Fi-Router",
"caracteristicas": [
"Direkte Peer-to-Peer-Kommunikation ohne Verbindungsaushandlung oder Access Point",
"Extrem geringe Übertragungsverzögerung: Latenzen im Millisekundenbereich",
"Unterstützung für Unicast- und Broadcast-Übertragungen",
"Sichere Frame-Verschlüsselung mit CCMP-Schlüsseln (AES-128)",
"Geringer Energieverbrauch, ideal für batteriebetriebene Sensoren",
"Rückwärtskompatibel mit allen ESP32- und ESP8266-Modellen",
"Nutzlast bis zu 250 Bytes pro Paket – ausreichend für Telemetrie und Schaltbefehle"
],
"casos_uso": [
"Fernbedienungen und Funkschalter mit sofortigem Aufwachen",
"Batteriebetriebene Sensornetzwerke mit periodischer Messwertübertragung",
"Steuerungen für Drohnen, Roboter und RC-Modelle",
"Industrielle Not-Aus-Taster mit kritischen Latenzanforderungen",
"Lokale Ausfallsicherung bei nicht verfügbarem WLAN-Netzwerk"
],
"exemplo": "/exemplos/esp-now.c",
"exemplos": "https://github.com/espressif/esp-now/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-now/en/latest/",
"repositorio": "https://github.com/espressif/esp-now",
"cor": "#E67E22"
},
"ESP-Zigbee-SDK": {
"nome": "ESP-Zigbee-SDK",
"icone": "🐝",
"nome_completo": "Espressif Zigbee Software Development Kit",
"descricao": "Offizielles SDK für die Entwicklung von Zigbee 3.0-Geräten auf SoCs mit 802.15.4-Funk (ESP32-H2 und ESP32-C6). Unterstützt Koordinator-, Router- und Endgeräte-Rollen.",
"linguagem": "C / C++",
"tipo": "Mesh & 802.15.4 Framework",
"funcao_principal": "Entwicklung von Geräten für Zigbee 3.0-Mesh-Netzwerke mit zertifizierter industrieller Interoperabilität",
"caracteristicas": [
"Konform mit den Spezifikationen Zigbee 3.0 und Zigbee PRO",
"Unterstützung aller Netzwerkrollen: Koordinator (ZC), Router (ZR) und Endgerät (ZED)",
"Energiesparende Sleepy-End-Device-Rollen (SED) für Batteriebetrieb",
"Unterstützung von Standardprofilen: Zigbee Home Automation (ZHA) und Light Link",
"Zigbee-zu-Wi-Fi/Ethernet-Gateway in Kombination von ESP32-H2 mit Zweit-SoC",
"Standardkonforme Zigbee-OTA-Cluster-Firmware-Updates",
"Nahtlose Integration mit ESP-IDF und Z-Stack-Kompatibilität"
],
"casos_uso": [
"Türkontakte, Bewegungsmelder und Wassersensoren im Batteriebetrieb",
"Interoperable Zigbee 3.0-Leuchtmittel, Dimmer und Wandschalter",
"Zigbee-zu-Ethernet/Wi-Fi-Gateways für Smart-Home-Zentralen",
"Industrielle Thermostate und Energiezähler",
"Erweiterung bestehender Installationen im standardisierten Zigbee-Ökosystem"
],
"exemplo": "/exemplos/esp-zigbee.c",
"exemplos": "https://github.com/espressif/esp-zigbee-sdk/tree/main/examples",
"documentacao": "https://docs.espressif.com/projects/esp-zigbee-sdk/en/latest/",
"repositorio": "https://github.com/espressif/esp-zigbee-sdk",
"cor": "#F1C40F"
},
"ESP-WHO": {
"nome": "ESP-WHO",
"icone": "👁️",
"nome_completo": "ESP-WHO Face Detection & Recognition Framework",
"descricao": "Computer-Vision-Framework für ESP32, optimiert für Kameramodule (OV2640, OV3660, OV5640) mit lokaler Gesichtserkennung und Identifikation.",
"linguagem": "C / C++",
"tipo": "Computer Vision & Edge AI",
"funcao_principal": "Eingebettete Bildverarbeitung mit Gesichtserkennung, Ausrichtung und Identifikation",
"caracteristicas": [
"Leichtgewichtige Inferenzmodelle, optimiert für ESP32 und ESP32-S3",
"Deep-Learning-basierte Gesichtserkennung mit Bestimmung von Gesichtsmerkmalen",
"Gesichtserkennung und Registrierung direkt im Gerätespeicher",
"Performanter Kameratreiber für DVP- und SPI-Busse",
"Unterstützung von Bildauflösungen von QVGA bis QSXGA",
"Vektorbeschleunigung durch dedizierte KI-Befehle des ESP32-S3",
"Integrierter HTTP-Videostreaming-Server für Debugging und Vorschau"
],
"casos_uso": [
"Biometrische Zugangskontrollen und intelligente Türschlösser",
"Video-Türklingeln mit Personen- und Anwesenheitserkennung",
"Personenzählung und Belegungsanalyse für Konferenzräume",
"Intelligente Sicherheitskameras mit lokaler Fehlalarmfilterung",
"Assistenzgeräte und Mensch-Maschine-Interaktion"
],
"exemplo": "/exemplos/esp-who.c",
"exemplos": "https://github.com/espressif/esp-who/tree/master/examples",
"documentacao": "https://github.com/espressif/esp-who#readme",
"repositorio": "https://github.com/espressif/esp-who",
"cor": "#1ABC9C"
},
"ESP-NN": {
"nome": "ESP-NN",
"icone": "🧠",
"nome_completo": "ESP Neural Network Acceleration Library",
"descricao": "Beschleunigungsbibliothek für neuronale Netze auf ESP32-SoCs zur Optimierung von Faltungskernen, Matrixmultiplikationen und Aktivierungsfunktionen für Edge-KI.",
"linguagem": "C / C++ / Asm",
"tipo": "Neural Network Kernel Library",
"funcao_principal": "Hochoptimierte Assembler-Kerne für neuronale Inferenz unter TensorFlow Lite for Microcontrollers",
"caracteristicas": [
"Assembler-Optimierungen unter Nutzung der SIMD-Vektorbefehle des ESP32-S3",
"Beschleunigte Operationen: 2D-Faltung, Depthwise Conv, Fully Connected und Pooling",
"Unterstützung für 8-Bit- (int8) und 16-Bit-Quantisierung (int16)",
"Nahtlose Integration als Optimierungs-Backend für TensorFlow Lite for Microcontrollers",
"Deutliche Reduzierung der Inferenzlatenz gegenüber generischen Implementierungen",
"Optimierter SRAM-Speicherbedarf für ressourcenbeschränkte Mikrocontroller",
"Unterstützung für ESP32, ESP32-S3 und RISC-V-Architekturen (C3, C6, P4)"
],
"casos_uso": [
"Edge-Vision-Modelle (Objekterkennung und Klassifikation)",
"Vibrations- und Akustikanomalieerkennung für vorausschauende Wartung",
"Klassifikation biometrischer Signale (EKG, PPG) auf Wearables",
"Gestenerkennung und Schnittstellen basierend auf Inertialsensoren (IMU)",
"Benutzerdefinierte Audiomodelle zur Erkennung spezifischer Signalmuster"
],
"exemplo": "/exemplos/esp-nn.c",
"exemplos": "https://github.com/espressif/esp-nn/tree/master/examples",
"documentacao": "https://github.com/espressif/esp-nn#readme",
"repositorio": "https://github.com/espressif/esp-nn",
"cor": "#8E44AD"
},
"ESP-DSP": {
"nome": "ESP-DSP",
"icone": "📊",
"nome_completo": "ESP Digital Signal Processing Library",
"descricao": "Offizielle DSP-Bibliothek für ESP32-SoCs mit Algorithmen für FFT, digitale Filterung, Matrixberechnungen und numerische Operationen.",
"linguagem": "C / Asm",
"tipo": "DSP & Math Library",
"funcao_principal": "Hochperformante mathematische Funktionen und digitale Signalverarbeitung mit Hardware-Optimierung",
"caracteristicas": [
"Schnelle Fourier-Transformation (FFT) für reelle und komplexe Daten mit Fensterfunktionen (Hann, Hamming, Blackman)",
"Optimierte digitale IIR- (Biquad) und FIR-Filter",
"Matrixoperationen: Multiplikation, Invertierung, Zerlegung und Transposition",
"Hardware-beschleunigte Gleitkomma- und Ganzzahl-Vektoroperationen",
"Generierung von Testsignalen: Sinus, weißes Rauschen und modulierte Signale",
"Assembler-Routinen für den Xtensa-Kern und Vektorinstruktionserweiterungen",
"Kompatibel mit ESP-IDF als native Komponente"
],
"casos_uso": [
"Echtzeit-Spektrumanalyse für Audio- und Schwingungsmessgeräte",
"Signalverarbeitung und Rauschfilterung für industrielle Sensoren",
"Regelungsalgorithmen für Motorsteuerungen und Wechselrichter",
"Intelligente Stromzähler mit Wirk- und Blindleistungsberechnung",
"Signalanalyse für Radarsensoren und Ultraschallmessungen"
],
"exemplo": "/exemplos/esp-dsp.c",
"exemplos": "https://github.com/espressif/esp-dsp/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-dsp/en/latest/",
"repositorio": "https://github.com/espressif/esp-dsp",
"cor": "#2C3E50"
},
"Rust-ESP": {
"nome": "Rust-ESP",
"icone": "🦀",
"nome_completo": "Rust on ESP32 Ecosystem",
"descricao": "Rust-Entwicklungsökosystem für ESP32-Mikrocontroller. Bietet Speichersicherheit ohne Garbage Collector, ein starkes Typsystem und moderne Ausdrucksstärke.",
"linguagem": "Rust",
"tipo": "Memory-Safe Modern Language",
"funcao_principal": "Entwicklung robuster Firmware mit Schutz vor Speicherbeschädigungen und garantierter Datenrennfreiheit bei Nebenläufigkeit",
"caracteristicas": [
"Zwei Entwicklungsansätze: no_std (Bare-Metal über esp-hal) und std (auf FreeRTOS über esp-idf-svc)",
"Offizielle Rust-Toolchain für Xtensa- und RISC-V-Architekturen",
"Garantierte Speichersicherheit zur Kompilierzeit",
"Modernes asynchrones Modell mit async/await für Netzwerk- und E/A-Aufgaben",
"Unterstützung für Wi-Fi-, BLE-, MQTT-, HTTP- und TLS-Stacks über Ökosystem-Crates",
"Kommandozeilenwerkzeug espflash zum Flashen und Überwachen von Entwicklungsboards",
"Direkte Integration mit Cargo und dem gesamten Rust-Open-Source-Ökosystem"
],
"casos_uso": [
"Industrielle kritische Firmware mit höchsten Zuverlässigkeitsanforderungen",
"Medizin- und Sicherheitsgeräte, bei denen Speicherfehler unzulässig sind",
"Netzwerk-Gateways mit sicherer Verarbeitung kryptografischer und TLS-Protokolle",
"Moderne eingebettete Anwendungen mit asynchroner Nebenläufigkeit",
"Projekte nach neuesten Standards des modernen Embedded Software Engineerings"
],
"exemplo": "/exemplos/rust-esp.rs",
"exemplos": "https://github.com/esp-rs/esp-idf-template",
"documentacao": "https://esp-rs.github.io/book/",
"repositorio": "https://github.com/esp-rs",
"cor": "#D35400"
},
"Arduino": {
"nome": "Arduino",
"icone": "♾️",
"nome_completo": "Arduino Core for ESP32",
"descricao": "Offizieller Arduino-Core für ESP32-SoCs. Bietet die vertraute setup()/loop()-API mit Zugriff auf Tausende Bibliotheken von Drittanbietern auf einem stabilen ESP-IDF-Fundament.",
"linguagem": "C++ (Arduino)",
"tipo": "Maker & Educational Framework",
"funcao_principal": "Schnelles Prototyping und zugängliche Projekterstellung mit dem weltweit größten Open-Source-Bibliotheksökosystem",
"caracteristicas": [
"Vertraute Struktur aus setup()-Initialisierung und loop()-Hauptschleife",
"Sofortiger Zugriff auf das riesige Repository der Arduino-Bibliotheken",
"Basiert im Hintergrund auf FreeRTOS und erlaubt eigene Tasks per xTaskCreate",
"Unterstützung für nahezu jedes ESP32-Entwicklungsboard am Markt",
"Intuitives Wi-Fi- und Bluetooth-Management (WiFi, BluetoothSerial, BLEDevice)",
"Einfache OTA-Firmware-Updates über die ArduinoOTA-Klasse",
"Kompatibel mit Arduino IDE, PlatformIO, VS Code und Arduino CLI"
],
"casos_uso": [
"Schnelles Prototyping von IoT-Projekten und Machbarkeitsstudien",
"Ausbildung, universitäre Lehre und Schulung in eingebetteten Systemen",
"Maker-Projekte und Do-It-Yourself-Elektronik",
"Geräte mit bestehenden Sensor- und Aktor-Bibliotheken",
"Interaktive Kunstinstallationen und Funktionsmodelle"
],
"exemplo": "/exemplos/arduino.ino",
"exemplos": "https://github.com/espressif/arduino-esp32/tree/master/libraries",
"documentacao": "https://docs.espressif.com/projects/arduino-esp32/en/latest/",
"repositorio": "https://github.com/espressif/arduino-esp32",
"cor": "#00979C"
},
"MicroPython": {
"nome": "MicroPython",
"icone": "🐍",
"nome_completo": "MicroPython for ESP32",
"descricao": "Schlanke und effiziente Python-3-Implementierung für Mikrocontroller. Ermöglicht interaktive Programmierung über REPL an der seriellen Schnittstelle ohne vorherige Kompilierung.",
"linguagem": "Python 3",
"tipo": "Interactive Scripting Engine",
"funcao_principal": "Schnelle und interaktive Entwicklung mit der Einfachheit von Python und unmittelbarem Hardwarezugriff",
"caracteristicas": [
"Vollständiger Python-3-Interpreter, optimiert für Mikrocontroller",
"Interaktive REPL-Konsole (Read-Eval-Print Loop) über serielle Schnittstelle oder Wi-Fi (WebREPL)",
"Virtuelles Dateisystem mit Unterstützung für .py-Dateien und vorkompilierte .mpy-Module",
"Intuitive Hardwaremodule: machine (Pin, ADC, PWM, I2C, SPI, UART, Timer, RTC)",
"Native Netzwerkunterstützung: network-Modul (Wi-Fi-Station und Access Point)",
"Asynchrone Programmierung mit dem Modul uasyncio",
"Offizielle Unterstützung aller ESP32-Varianten mit vorkompilierten Firmware-Binärdateien"
],
"casos_uso": [
"Programmierausbildung und MINT-Lernprojekte",
"Schnelles Prototyping und Sensortests ohne Kompilierzyklen",
"Gerätesteuerung und Skripte, die ohne Neu-Flashen anpassbar sind",
"Eigenständige Datenlogger und kompakte HTTP-/WebSocket-Server",
"Laborautomatisierung und Auswertung von Sensordaten"
],
"exemplo": "/exemplos/micropython.py",
"exemplos": "https://github.com/micropython/micropython/tree/master/examples",
"documentacao": "https://docs.micropython.org/en/latest/esp32/quickref.html",
"repositorio": "https://github.com/micropython/micropython",
"cor": "#2B5B84"
}
}
+732
View File
@@ -0,0 +1,732 @@
{
"ESP32": {
"nome_completo": "ESP32 (Clássico)",
"icone": "🔷",
"descricao": "Der Pionier der Reihe mit Xtensa-Dual-Core, Wi-Fi 4 und klassischem Bluetooth/BLE. Empfohlen für klassische Audioprojekte und etablierte IoT-Gateways.",
"arquitetura": "32-Bit-Xtensa®-LX6-Dual-Core",
"nucleos": "1 (Single-core) ou 2 (Dual-core)",
"frequencia": "Bis zu 240 MHz",
"coprocessador_ulp": "Ja",
"seguranca": {
"aes": "AES-128/192/256",
"sha": "SHA-1/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 4096 bits)",
"ecc": "Nein",
"ecdsa": "Nein",
"hmac": "Nein",
"assinatura_digital": "Nein",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "Ja (AES-256, Legacy-Verfahren)",
"secure_boot": "V1 (AES, Legacy); V2 (RSA-3072, RSA-PSS) ab Revision v3.0 (ECO3)",
"protecao_dpa": "Nein"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, bis zu 150 Mbps)",
"bluetooth": "Bluetooth 4.2 BR/EDR (Clássico) und Bluetooth LE (dual mode)",
"ethernet": "Ja (Ethernet-MAC integriert)",
"memoria_sram": "520 KB",
"memoria_sram_rtc": "16 KB (dividida em RTC FAST e RTC SLOW)",
"memoria_rom": "448 KB (für Boot- und Core-Funktionen)",
"flash_externa": "Bis zu 16 MB über QSPI",
"psram_externa": "Bis zu 8 MB über QSPI (in spezifischen Modulen wie WROVER)",
"gpio": "34",
"adc": "2x SAR-ADC mit 12 Bit, bis zu 18 Kanäle",
"dac": "2x DAC de 8 bits",
"touch": "10 kapazitive Kanäle",
"uart": "3",
"spi": "4 (SPI, HSPI, VSPI - 2 für Flash/PSRAM nutzbar)",
"i2c": "2",
"i2s": "2",
"pwm": "LED-PWM (bis zu 16 Kanäle), Motor-PWM",
"ethernet_mac": "1 (requer PHY externo)",
"can": "1 (CAN 2.0, TWAI®)",
"sdio": "1 (SD/SDIO/MMC Host), 1 (SDIO/SPI Slave)",
"sensor_hall": "1 (interno)",
"sensor_temperatura": "Nein (retirado do datasheet em 2018; sem driver no ESP-IDF)",
"consumo_energia": {
"active_cpu_240mhz": "30-68 mA",
"active_wifi_tx": "180-240 mA",
"modem_sleep": "20-44 mA",
"light_sleep": "0.8 mA",
"deep_sleep": "10-150 µA",
"hibernation": "5 µA"
},
"temperatura_operacao": "-40°C a 125°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Externes JTAG (erfordert Sonde, z. B. ESP-PROG)",
"esp_idf_minimo": "Seit Beginn (v3.x und früher)",
"arduino_core": "Ja (147 definições de placa no core oficial)",
"encapsulamento": "QFN48 (6×6 mm) und QFN48 (5×5 mm)",
"modulos": "ESP32-MINI-1, ESP32-PICO-MINI-02, ESP32-PICO-V3, ESP32-PICO-V3-02 e mais 11",
"datasheet": "https://documentation.espressif.com/esp32_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html",
"placa": "/placas/esp32.png",
"cor": "#007bff"
},
"ESP32-S2": {
"nome_completo": "ESP32-S2",
"icone": "🔒",
"descricao": "Single-Core-SoC mit nativer USB-OTG-Schnittstelle, erweiterter Hardware-Sicherheit und bis zu 43 GPIOs. Entwickelt für einfache Display-Schnittstellen und sichere USB-Peripherie.",
"arquitetura": "32-Bit-Xtensa®-LX7-Single-Core",
"nucleos": "1 (Single-core)",
"frequencia": "Bis zu 240 MHz",
"coprocessador_ulp": "Ja (RISC-V)",
"seguranca": {
"aes": "AES-128/192/256 com GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 4096 bits)",
"ecc": "Nein",
"ecdsa": "Nein",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "Nein"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, bis zu 150 Mbps)",
"bluetooth": "Nein",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "128 KB",
"flash_externa": "Bis zu 1 GB über QSPI",
"psram_externa": "Bis zu 1 GB über QSPI/Octal SPI",
"gpio": "43",
"adc": "2x SAR-ADC, bis zu 20 Kanäle: 13-Bit-Ausgabe (0–8191, einzigartig in der Familie), effektive Auflösung von 12 Bit ab Revision v1.0 (Erratum ADC-112)",
"dac": "2x DAC de 8 bits",
"touch": "14 kapazitive Kanäle",
"uart": "2",
"spi": "4 (SPI0/1 für Flash, SPI2/3 für allgemeine Zwecke)",
"i2c": "2",
"i2s": "1",
"pwm": "LED-PWM (bis zu 8 Kanäle)",
"usb": "1 (USB OTG 1.1 Full-Speed)",
"lcd": "8/16-Bit-LCD-Schnittstelle",
"camera": "8/16-Bit-DVP-Kameraschnittstelle",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active_wifi_tx": "160-310 mA",
"modem_sleep_cpu_160mhz": "14-24 mA",
"light_sleep": "750 µA",
"deep_sleep": "20-190 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Externes JTAG (erfordert Sonde, z. B. ESP-PROG)",
"esp_idf_minimo": "v4.2",
"arduino_core": "Ja (26 definições de placa no core oficial)",
"encapsulamento": "QFN56 (7×7 mm)",
"modulos": "ESP32-S2-MINI-1, ESP32-S2-MINI-2, ESP32-S2-SOLO, ESP32-S2-SOLO-2 e mais 4",
"datasheet": "https://documentation.espressif.com/esp32-s2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html",
"placa": "/placas/esp32-s2.png",
"cor": "#28a745"
},
"ESP32-S3": {
"nome_completo": "ESP32-S3",
"icone": "🤖",
"descricao": "Hochleistungs-Dual-Core mit Vektorbefehlen für KI, nativem USB und bis zu 45 GPIOs. Die Standardwahl für Computer Vision, Sprachverarbeitung und anspruchsvolle HMIs.",
"arquitetura": "32-Bit-Xtensa®-LX7-Dual-Core",
"nucleos": "2 (Dual-core)",
"frequencia": "Bis zu 240 MHz",
"coprocessador_ulp": "Ja (RISC-V)",
"aceleradores_ia": "Ja (Vektorbefehle für KI)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 4096 bits)",
"ecc": "Nein",
"ecdsa": "Nein",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "Nein"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, bis zu 150 Mbps)",
"bluetooth": "Bluetooth 5 (LE) und Bluetooth Mesh",
"memoria_sram": "512 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "384 KB",
"flash_externa": "Bis zu 1 GB über QSPI/Octal SPI",
"psram_externa": "Bis zu 1 GB über QSPI/Octal SPI",
"gpio": "45",
"adc": "2x SAR-ADC mit 12 Bit, bis zu 20 Kanäle",
"dac": "Nein",
"touch": "14 kapazitive Kanäle",
"uart": "3",
"spi": "4 (SPI0/1 für Flash, SPI2/3 für allgemeine Zwecke)",
"i2c": "2",
"i2s": "2",
"pwm": "LED-PWM (bis zu 8 Kanäle), Motor-PWM (6 Kanäle)",
"usb": "1 (USB OTG 1.1 Full-Speed) + 1 (USB Serial/JTAG)",
"lcd": "8/16-Bit-RGB-LCD-Schnittstelle",
"camera": "8/16-Bit-DVP-Kameraschnittstelle",
"sdio": "1 (SD/SDIO/MMC Host)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "78 mW (~24 mA @3.3V)",
"modem_sleep": "13-42 mA (40-80 MHz, je nach Last)",
"light_sleep": "240 µA (+40 a 200 µA für PSRAM)",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C a 65/85/105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v4.4",
"arduino_core": "Ja (158 definições de placa no core oficial)",
"encapsulamento": "QFN56 (7×7 mm)",
"modulos": "ESP32-S3-MINI-1, ESP32-S3-WROOM-1, ESP32-S3-WROOM-2",
"datasheet": "https://documentation.espressif.com/esp32-s3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/get-started/index.html",
"placa": "/placas/esp32-s3.png",
"cor": "#fd7e14"
},
"ESP32-S31": {
"nome_completo": "ESP32-S31",
"icone": "🌀",
"descricao": "Fortschrittlicher SoC, optimiert für generative KI und Vision-Edge-Verarbeitung, der hochfrequente Xtensa-Dual-Cores mit modernster Hardware-Sicherheit verbindet.",
"arquitetura": "RISC-V dual-core de 32 bits (HP) + RISC-V single-core (LP)",
"nucleos": "2 (Dual-core HP) + 1 (Single-core LP)",
"frequencia": "Bis zu 320 MHz",
"coprocessador_ulp": "Ja (RISC-V, LP CPU de 40 MHz)",
"aceleradores_ia": "Sim (Custom AI and DSP extension XespV)",
"seguranca": {
"aes": "AES-128/256 com GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 4096 bits)",
"ecc": "Ja (P-192, P-256, P-384)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Ja",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "Ja"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5.4 LE und Bluetooth Classic",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Ja",
"memoria_sram": "512 KB (HP SRAM)",
"memoria_sram_rtc": "32 KB (LP SRAM)",
"memoria_rom": "320 KB",
"flash_externa": "Bis zu 256 MB über QSPI",
"psram_externa": "16 MB oder 32 MB Octal-DDR, nur im Gehäuse integriert (NRV16, NRV32)",
"gpio": "60",
"adc": "2x SAR-ADC mit 12 Bit, bis zu 16 Kanäle",
"dac": "Ja (2x DAC de 10 bits e 2x DAC de 12 bits)",
"touch": "14 kapazitive Kanäle",
"uart": "5 (4 UART + 1 LP UART)",
"spi": "7 (6 SPI + 1 LP SPI)",
"i2c": "3 (2 I2C + 1 LP I2C)",
"i2s": "2",
"pwm": "LED-PWM (bis zu 8 Kanäle), Motor-PWM (MCPWM)",
"usb": "1 (USB 2.0 High-Speed OTG e USB Serial/JTAG)",
"can": "Ja (CAN FD Controller)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "Konfigurierbarer, leistungsoptimierter Hochleistungsbetrieb",
"light_sleep": "0.1-0.8 mA",
"deep_sleep": "Baixo consumo com LP CPU ativa"
},
"temperatura_operacao": "-40°C a 85°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v6.1 in Vorschau; offizielle Unterstützung ab v6.1.1",
"arduino_core": "Noch nicht vom arduino-esp32-Core unterstützt",
"encapsulamento": "QFN80 (8×8 mm)",
"modulos": "ESP32-S31-WROOM-1, ESP32-S31-WROOM-3",
"datasheet": "https://documentation.espressif.com/esp32-s31_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s31_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s31/get-started/index.html",
"placa": "/placas/esp32-s31.png",
"cor": "#ff2a5f",
"sdio": "1 (SDIO Host 3.0)"
},
"ESP32-C2": {
"nome_completo": "ESP32-C2 (ESP8684)",
"icone": "🌱",
"descricao": "Kompakter und kostengünstiger RISC-V-Chip für einfache Sensoren und den direkten Ersatz des ESP8266 in volumenstarken Massenproduktionen.",
"arquitetura": "RISC-V single-core de 32 bits",
"nucleos": "1 (Single-core)",
"frequencia": "Bis zu 120 MHz",
"seguranca": {
"aes": "Nein",
"sha": "SHA-1/224/256",
"rsa": "Nein",
"ecc": "Ja (P-192, P-256)",
"ecdsa": "Nein",
"hmac": "Nein",
"assinatura_digital": "Nein",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (ECDSA P-192 ou P-256)",
"protecao_dpa": "Nein"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, bis zu 72.2 Mbps)",
"bluetooth": "Bluetooth 5.3 LE (certificado)",
"memoria_sram": "272 KB (davon 16 KB Cache)",
"memoria_sram_rtc": "Nein",
"memoria_rom": "576 KB",
"flash_externa": "Bis zu 16 MB über QSPI, jedoch bei im Handel erhältlichen Varianten nicht verfügbar (ESP8684H2X/H4X haben 2 MB oder 4 MB im Gehäuse und führen keine Flash-Pins heraus)",
"psram_externa": "Nein",
"gpio": "14",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 5 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "2",
"spi": "3 (SPI0/1 für interne Flash, SPI2 für allgemeine Zwecke)",
"i2c": "1 (Master-only)",
"i2s": "Nein",
"pwm": "LED-PWM (bis zu 6 Kanäle)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active_cpu_120mhz": "10,7-15,6 mA (modem-sleep)",
"light_sleep": "140 µA",
"deep_sleep": "5 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Externes JTAG (erfordert Sonde, z. B. ESP-PROG)",
"esp_idf_minimo": "v5.0",
"arduino_core": "Ja (1 definições de placa no core oficial)",
"encapsulamento": "QFN24 (4×4 mm)",
"modulos": "ESP8684-MINI-1, ESP8684-WROOM-01C, ESP8684-WROOM-02C, ESP8684-WROOM-02UC e mais 5",
"datasheet": "https://documentation.espressif.com/esp32-c2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c2/get-started/index.html",
"placa": "/placas/esp32-c2.png",
"cor": "#8c52ff"
},
"ESP32-C3": {
"nome_completo": "ESP32-C3",
"icone": "💎",
"descricao": "Kostengünstiger RISC-V-Single-Core, anschlusskompatibel zum ESP8266. Bietet Wi-Fi 4 und Bluetooth 5 (BLE) für kompakte vernetzte Geräte.",
"arquitetura": "RISC-V single-core de 32 bits",
"nucleos": "1 (Single-core)",
"frequencia": "Bis zu 160 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Ja (RSA/MPI bis zu 3072 bits)",
"ecc": "Nein",
"ecdsa": "Nein",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072), ab Revision v0.3 (ECO3)",
"protecao_dpa": "Nein"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, bis zu 150 Mbps)",
"bluetooth": "Bluetooth 5 (LE) und Bluetooth Mesh",
"memoria_sram": "400 KB",
"memoria_sram_rtc": "8 KB",
"memoria_rom": "384 KB",
"flash_externa": "Bis zu 16 MB über QSPI",
"psram_externa": "Nein",
"gpio": "22",
"adc": "2x SAR-ADC mit 12 Bit, bis zu 6 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "2",
"spi": "3 (SPI0/1 für Flash, SPI2 für allgemeine Zwecke)",
"i2c": "1",
"i2s": "1",
"pwm": "LED-PWM (bis zu 6 Kanäle)",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active_cpu_160mhz": "20 mA",
"active_wifi_tx_peak": "335 mA",
"modem_sleep_cpu_160mhz": "16-28 mA",
"light_sleep": "130 µA",
"deep_sleep": "5 µA"
},
"temperatura_operacao": "-40 °C bis 105 °C (85 °C beim ESP32-C3FN4)",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v4.3",
"arduino_core": "Ja (29 definições de placa no core oficial)",
"encapsulamento": "QFN32 (5×5 mm) und QFN28 (4×4 mm)",
"modulos": "ESP32-C3-MINI-1, ESP32-C3-WROOM-02",
"datasheet": "https://documentation.espressif.com/esp32-c3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html",
"placa": "/placas/esp32-c3.png",
"cor": "#20c997"
},
"ESP32-C5": {
"nome_completo": "ESP32-C5",
"icone": "📶",
"descricao": "Erster Dualband-SoC (2,4 GHz und 5 GHz) der C-Serie mit RISC-V-Architektur. Konzipiert für Industrieumgebungen mit hoher Kanalauslastung im 2,4-GHz-Band.",
"arquitetura": "RISC-V single-core de 32 bits (HP) + RISC-V single-core (LP)",
"nucleos": "1 (Single-core HP) + 1 (Single-core LP)",
"frequencia": "Bis zu 240 MHz",
"coprocessador_ulp": "Ja (RISC-V, LP CPU de 48 MHz)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 3072 bits)",
"ecc": "Ja (P-192, P-256, P-384)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Ja",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072 ou ECDSA P-256/P-384)",
"protecao_dpa": "Ja"
},
"wifi": "Wi-Fi 6 (802.11ax) Dualband 2.4 GHz e 5 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth Core 6.0 certificado)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Ja",
"memoria_sram": "384 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "320 KB",
"flash_externa": "Bis zu 16 MB über QSPI",
"psram_externa": "Ja, via SPI (controlador de flash/PSRAM com cache)",
"gpio": "29",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 6 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "3 (2 UART + 1 LP UART)",
"spi": "3",
"i2c": "2 (1 I2C + 1 LP I2C)",
"i2s": "1",
"pwm": "LED-PWM (bis zu 6 Kanäle), Motor-PWM",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active_wifi": "bis zu 377 mA (TX bei 5 GHz)",
"light_sleep": "60-250 µA",
"deep_sleep": "12 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v5.5.2",
"arduino_core": "Ja (10 definições de placa no core oficial)",
"encapsulamento": "QFN48 (6×6 mm)",
"modulos": "ESP32-C5-MINI-1, ESP32-C5-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c5_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c5_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/get-started/index.html",
"placa": "/placas/esp32-c5.png",
"cor": "#6f42c1",
"sdio": "1 (SDIO Slave, a partir da revisão v1.0)",
"can": "2 (CAN FD)"
},
"ESP32-C6": {
"nome_completo": "ESP32-C6",
"icone": "🌐",
"descricao": "Moderner RISC-V-SoC mit Wi-Fi 6, Bluetooth 5 (LE) und integriertem IEEE-802.15.4-Funk. Ideal für stromsparende Smart-Home-Knoten nach Matter- und Thread-Standard.",
"arquitetura": "RISC-V single-core de 32 bits (HP) + RISC-V single-core (LP)",
"nucleos": "1 (Single-core HP) + 1 (Single-core LP)",
"frequencia": "Bis zu 160 MHz",
"coprocessador_ulp": "Ja (RISC-V, LP CPU de 20 MHz)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Ja (RSA/MPI bis zu 3072 bits)",
"ecc": "Ja (P-192, P-256)",
"ecdsa": "Nein",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072 ou ECDSA)",
"protecao_dpa": "Ja"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth 5.3 certificado)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.3)",
"matter": "Ja",
"memoria_sram": "512 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "320 KB",
"flash_externa": "Bis zu 16 MB über QSPI",
"psram_externa": "Nein",
"gpio": "30",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 7 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "3 (2 UART + 1 LP UART)",
"spi": "3",
"i2c": "2 (1 I2C + 1 LP I2C)",
"i2s": "1",
"pwm": "LED-PWM (bis zu 6 Kanäle), Motor-PWM",
"usb": "1 (USB Serial/JTAG)",
"sdio": "1 (SDIO 2.0 Slave)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active_wifi6": "252-354 mA (TX)",
"light_sleep": "35-180 µA",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v5.1",
"arduino_core": "Ja (21 definições de placa no core oficial)",
"encapsulamento": "QFN40 (5×5 mm) und QFN32 (5×5 mm)",
"modulos": "ESP32-C6-MINI-1, ESP32-C6-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c6_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c6_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/get-started/index.html",
"placa": "/placas/esp32-c6.png",
"cor": "#17a2b8"
},
"ESP32-C61": {
"nome_completo": "ESP32-C61",
"icone": "🛰️",
"descricao": "Kostengünstige Variante des C6, optimiert für Wi-Fi 6- und BLE-Endknoten ohne 802.15.4-Funk, ideal für großflächig vernetzte Sensoren.",
"arquitetura": "RISC-V single-core de 32 bits",
"nucleos": "1 (Single-core)",
"frequencia": "Bis zu 160 MHz",
"seguranca": {
"aes": "Nein",
"sha": "SHA-1/224/256",
"rsa": "Nein",
"ecc": "Ja (P-192, P-256)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Nein",
"assinatura_digital": "Nein",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (ECDSA)",
"protecao_dpa": "Ja"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth Core 6.0 certificado)",
"zigbee_thread": "Nein",
"matter": "Ja (via Wi-Fi)",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "Nein",
"memoria_rom": "256 KB",
"flash_externa": "Bis zu 16 MB über QSPI (Modelle mit 4 MB oder 8 MB im Gehäuse integriert)",
"psram_externa": "Bis zu 16 MB über QSPI (Modelle mit 2 MB oder 8 MB im Gehäuse integriert)",
"gpio": "30",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 4 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "3",
"spi": "3 (2 für Flash/PSRAM, 1 für allgemeine Zwecke)",
"i2c": "1",
"i2s": "1",
"pwm": "LED-PWM (bis zu 6 Kanäle)",
"usb": "1 (USB Serial/JTAG)",
"sdio": "1 (SDIO 2.0 Slave)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "240-360 mA (TX)",
"light_sleep": "50-200 µA",
"deep_sleep": "10 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v5.5.2",
"arduino_core": "Ja (1 definições de placa no core oficial)",
"encapsulamento": "QFN40 (5×5 mm) oder LGA40 (5×5 mm)",
"modulos": "ESP32-C61-MINI-1, ESP32-C61-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c61_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c61_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c61/get-started/index.html",
"placa": "/placas/esp32-c61.png",
"cor": "#0dcaf0"
},
"ESP32-P4": {
"nome_completo": "ESP32-P4",
"icone": "⚡",
"descricao": "Hochleistungs-Mikrocontroller ohne integriertes Funkmodul mit 400-MHz-RISC-V-Dual-Core, MIPI-CSI/DSI-Schnittstellen und erweiterter Sicherheit für anspruchsvolle HMIs und Gateways.",
"arquitetura": "RISC-V de 32 bits dual-core de alto desempenho (HP) + single-core de baixo consumo (LP)",
"nucleos": "2 (Dual-core HP) + 1 (Single-core LP)",
"frequencia": "Bis zu 400 MHz (HP, Revision v3.x; 360 MHz bei v1.x); LP bis zu 40 MHz",
"coprocessador_ulp": "Ja (RISC-V, LP CPU de 40 MHz)",
"aceleradores_ia": "Sim (Vector Instructions, aceleradores de IA)",
"seguranca": {
"aes": "AES-128/256 com GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Ja (RSA/MPI bis zu 4096 bits)",
"ecc": "Ja (P-192, P-256, P-384)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Ja",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072 ou ECDSA)",
"protecao_dpa": "Nein"
},
"wifi": "Nein",
"bluetooth": "Nein",
"ethernet": "Ja (Ethernet-MAC integriert)",
"memoria_sram": "768 KB",
"memoria_sram_rtc": "32 KB",
"memoria_rom": "128 KB (HP ROM) + 16 KB (LP ROM)",
"flash_externa": "Bis zu 128 MB über QSPI/Octal SPI",
"psram_externa": "16 MB oder 32 MB im Gehäuse integriert (OPI/HPI, 1,8 V)",
"gpio": "55",
"adc": "2x SAR-ADC mit 12 Bit, bis zu 14 Kanäle",
"dac": "Nein",
"touch": "Ja (sensor de toque capacitivo)",
"uart": "6 (5 UART + 1 LP UART)",
"spi": "3",
"i2c": "3 (2 I2C + 1 LP I2C)",
"i2s": "4 (3 I2S + 1 LP I2S)",
"pwm": "LED-PWM (bis zu 8 Kanäle), Motor-PWM (6 Kanäle)",
"usb": "USB 2.0 High-Speed OTG + USB 2.0 Full-Speed OTG + USB Serial/JTAG",
"mipi_csi": "MIPI-CSI-Kameraschnittstelle",
"mipi_dsi": "MIPI-DSI-Schnittstelle für Displays",
"lcd": "8/16/24-Bit-LCD-Schnittstelle",
"camera": "8/16-Bit-DVP-Kameraschnittstelle",
"sdio": "1 SD/MMC-Host-Controller (SDHOST)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "15-150 mA (40 bis 400 MHz, je nach Last)",
"light_sleep": "75-800 µA",
"deep_sleep": "12 µA"
},
"temperatura_operacao": "-40°C a 85°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v5.3",
"arduino_core": "Ja (7 definições de placa no core oficial)",
"encapsulamento": "QFN104 (10×10 mm)",
"modulos": "Kein Modul im offiziellen Katalog (nur nackter Chip)",
"datasheet": "https://documentation.espressif.com/esp32-p4-chip-revision-v1.3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-p4-chip-revision-v1.3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/get-started/index.html",
"placa": "/placas/esp32-p4.png",
"cor": "#ffc107"
},
"ESP32-H2": {
"nome_completo": "ESP32-H2",
"icone": "🔋",
"descricao": "Ultra-Low-Power-Chip ohne Wi-Fi, ausgelegt für Zigbee 3.0, Thread 1.3 und Matter über 802.15.4 sowie Bluetooth 5.4 LE. Perfekt für batteriebetriebene Sensoren.",
"arquitetura": "RISC-V single-core de 32 bits",
"nucleos": "1 (Single-core)",
"frequencia": "Bis zu 96 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Ja (RSA/MPI bis zu 3072 bits)",
"ecc": "Ja (P-192, P-256)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Ja",
"assinatura_digital": "Ja",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072 ou ECDSA)",
"protecao_dpa": "Ja"
},
"wifi": "Nein",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth 5.3 certificado)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Ja",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "4 KB (LP Memory)",
"memoria_rom": "128 KB",
"flash_externa": "Bis zu 16 MB über QSPI",
"psram_externa": "Nein",
"gpio": "19",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 5 Kanäle",
"dac": "Nein",
"touch": "Nein",
"uart": "2",
"spi": "3",
"i2c": "2",
"i2s": "1",
"pwm": "LED-PWM (bis zu 6 Kanäle)",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "24-140 mA (Funk, von -24 a 20 dBm)",
"light_sleep": "25-85 µA",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "-40°C a 150°C",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v5.1",
"arduino_core": "Ja (3 definições de placa no core oficial)",
"encapsulamento": "QFN32 (4×4 mm)",
"modulos": "ESP32-H2-MINI-1, ESP32-H2-WROOM-02C",
"datasheet": "https://documentation.espressif.com/esp32-h2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-h2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/get-started/index.html",
"placa": "/placas/esp32-h2.png",
"cor": "#6c757d"
},
"ESP32-H4": {
"nome_completo": "ESP32-H4",
"icone": "🛡️",
"descricao": "Weiterentwicklung der 802.15.4-Reihe mit RISC-V-Dual-Core, Bluetooth 5.4 und erweiterter Funkreichweite, optimiert für Thread-Border-Router und Gateways.",
"status_documentacao": "Vorläufige Dokumentation: Espressif hat noch kein Datenblatt oder technisches Handbuch für den ESP32-H4 veröffentlicht. Die folgenden Daten stammen aus der offiziellen Produktankündigung und den Hardwaredefinitionen (soc_caps) von ESP-IDF und können sich bis zur Veröffentlichung ändern.",
"arquitetura": "RISC-V dual-core de 32 bits",
"nucleos": "2 (Dual-core)",
"frequencia": "Bis zu 96 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "Nein",
"ecc": "Ja (P-192, P-256, P-384)",
"ecdsa": "Ja (deterministischer Modus, RFC 6979)",
"hmac": "Ja",
"assinatura_digital": "Nein",
"key_manager": "Nein",
"rng": "Ja (TRNG Hardware-TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "Ja auf Hardware-Ebene; in ESP-IDF noch nicht aktiviert",
"protecao_dpa": "Nein"
},
"wifi": "Nein",
"bluetooth": "Bluetooth 5.4 LE (Bluetooth-6.0-zertifiziert; LE Audio, isochrone Kanäle BIS/CIS, PAwR, Connection Subrating und Direction Finding AoA/AoD)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Ja",
"memoria_sram": "384 KB",
"memoria_sram_rtc": "Sim (LP SRAM)",
"memoria_rom": "128 KB",
"flash_externa": "Ja, über QSPI (4 MB im Gehäuse des ESP32-H4HF4 integriert)",
"psram_externa": "Ja (2 MB im Gehäuse des ESP32-H4HR2 integriert)",
"gpio": "40",
"adc": "1x SAR-ADC mit 12 Bit, bis zu 5 Kanäle",
"dac": "Nein",
"touch": "15 kapazitive Kanäle (Version 3, mit Wasserfestigkeit und Näherungserkennung)",
"uart": "2",
"spi": "3",
"i2c": "2",
"i2s": "1",
"pwm": "LED-PWM (bis zu 8 Kanäle), Motor-PWM (MCPWM)",
"can": "1 (CAN 2.0, TWAI®)",
"usb": "1 (USB OTG 1.1) + 1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (interno)",
"consumo_energia": {
"active": "Nicht bekannt gegeben (vorläufige Dokumentation)"
},
"temperatura_operacao": "-40°C a 105°C",
"temperatura_armazenamento": "Nicht bekannt gegeben (vorläufige Dokumentation)",
"depuracao": "Integriertes JTAG über USB (keine externe Sonde erforderlich)",
"esp_idf_minimo": "v6.0 in Vorschau (ohne stabile Unterstützung)",
"arduino_core": "Noch nicht vom arduino-esp32-Core unterstützt",
"encapsulamento": "QFN56 (6×6 mm)",
"modulos": "ESP32-H4-WROOM-1",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32h4/get-started/index.html",
"cor": "#e83e8c"
}
}
+422
View File
@@ -0,0 +1,422 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"RF antenna connection (Wi-Fi and Bluetooth)"
],
"categorias": [
"Antenna",
"RF"
],
"avisos": [
"Dedicated RF pin. Avoid long traces without 50-ohm impedance matching."
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analog power supply de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V (3.0V to 3.6V)",
"Powers analog and RF circuits of the chip"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analog power supply de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V (3.0V to 3.6V)",
"Powers analog and RF circuits of the chip"
]
},
{
"numero": "4",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analog input pin ADC1 Channel 0"
]
},
{
"numero": "5",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO1",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analog input pin ADC1 Channel 1"
]
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI"
],
"avisos": [
"Mapped to SPI MISO (FSPIQ) by default during flash initialization"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Enable chip (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Active High. Pull high to enable chip boot.",
"Do not leave this pin floating. Use an external RC delay circuit for stable boot."
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Analog input pin ADC1 Channel 3"
]
},
{
"numero": "9",
"nome": "GPIO4",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO4",
"MTMS",
"FSPIQ",
"ADC1_CH4"
],
"categorias": [
"GPIO",
"JTAG",
"SPI",
"ADC"
],
"avisos": [
"Multifunction pin: JTAG MTMS, SPI2 MISO, and ADC1 Channel 4.",
"Can be used for JTAG debugging together with other JTAG pins."
]
},
{
"numero": "10",
"nome": "GPIO5",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO5",
"MTDI",
"FSPIWP"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunction pin: JTAG MTDI and SPI2 Write Protect (FSPIWP)."
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"RTC domain and low-power I/O power supply"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V"
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO6",
"MTCK",
"FSPICLK"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunction pin: JTAG MTCK and SPI2 Clock (FSPICLK)."
]
},
{
"numero": "13",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO7",
"MTDO",
"FSPID"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Multifunction pin: JTAG MTDO and SPI2 MOSI (FSPID)."
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping pin for boot control.",
"Together with GPIO9, selects SoC boot mode (must be high/1 during reset for Joint Download Boot if GPIO9=0)."
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Primary Strapping pin. High level (1) at reset activates SPI Boot (default via weak pull-up).",
"Low level (0) at reset puts chip into UART/SPI download mode."
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Multifunction pin: SPI2 Chip Select 0 (FSPICS0)."
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Digital power supply da CPU e IOs correspondentes (3.3V)"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V"
]
},
{
"numero": "18",
"nome": "GPIO18",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO18"
],
"categorias": [
"GPIO"
]
},
{
"numero": "19",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO19",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 receive pin (Serial RX by default for flashing and monitoring)."
]
},
{
"numero": "20",
"nome": "GPIO20",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO20",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 transmit pin (Serial TX by default for flashing and monitoring)."
]
},
{
"numero": "21",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"3.3V analog input power supply"
],
"categorias": [
"Power"
]
},
{
"numero": "22",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"External crystal oscillator connection (Output)"
],
"categorias": [
"Clock"
]
},
{
"numero": "23",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"External crystal oscillator connection (Input)"
],
"categorias": [
"Clock"
]
},
{
"numero": "24",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"3.3V analog input power supply"
],
"categorias": [
"Power"
]
},
{
"numero": "25",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Center ground pad (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Must be properly soldered to the PCB ground plane (GND) for stable performance and thermal dissipation."
]
}
]
+643
View File
@@ -0,0 +1,643 @@
[
{
"numero": "1",
"nome": "LNA_IN",
"tipo": "analog",
"funcoes": [
"RF signals input/output (Wi-Fi and Bluetooth) to antenna"
],
"categorias": [
"Antenna"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "3",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "4",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO0",
"XTAL_32K_P",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
]
},
{
"numero": "5",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
]
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"This pin does not set boot mode, but connecting it with a pull-up is recommended to prevent glitches (see datasheet section 3.1)"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Enable chip"
],
"categorias": [
"Power"
],
"avisos": [
"Pulling this pin high enables chip operation",
"Pulling this pin low disables chip operation",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input"
]
},
{
"numero": "9",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO4",
"ADC1_CH4",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "10",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO5",
"ADC2_CH0",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"Low-power domain and partial digital domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO7",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input with internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Digital domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "18",
"nome": "VDD_SPI",
"tipo": "power",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"Internal/external flash power supply input/output",
"GPIO11"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details",
"Can only be used as GPIO if flash memory is powered by an external supply"
]
},
{
"numero": "19",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO12",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "20",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO13",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "21",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO14",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "22",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO15",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "23",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO16",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "24",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "25",
"nome": "GPIO18",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO18",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "26",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO19",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "27",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO20",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "28",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO21",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"After reset, this pin will have internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "29",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negative clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.2 for analog pin details"
]
},
{
"numero": "30",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positive clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.2 for analog pin details"
]
},
{
"numero": "31",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "32",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
}
]
+944
View File
@@ -0,0 +1,944 @@
[
{
"numero": "1",
"nome": "VDDA6",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "2",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
},
{
"numero": "3",
"nome": "VDDA7",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "4",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negative clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.3 for analog pin details"
]
},
{
"numero": "5",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positive clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.3 for analog pin details"
]
},
{
"numero": "6",
"nome": "VDDA8",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "7",
"nome": "CHIP_PU",
"tipo": "analog",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"Enable chip"
],
"categorias": [
"Power"
],
"avisos": [
"Pulling this pin high enables chip operation",
"Pulling this pin low disables chip operation",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "8",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Low-power digital domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "9",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
]
},
{
"numero": "10",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
]
},
{
"numero": "11",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"LP_I2C_SDA",
"ADC1_CH1",
"FSPIQ",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"SPI",
"JTAG",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"I2C_SDA function is available in low-power (LP) mode",
"Pin used for debugging",
"Used to control crystal oscillator frequency (see datasheet section 3.5)"
]
},
{
"numero": "12",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"LP_I2C_SCL",
"ADC1_CH2",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"JTAG",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"I2C_SDA function is available in low-power (LP) mode",
"Pin used for debugging",
"Used to control SDIO Slave timing (see datasheet section 3.2)"
]
},
{
"numero": "13",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "14",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH4",
"FSPIWP",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "15",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"LP_GDIO6",
"ADC1_CH5",
"FSPICLK"
],
"categorias": [
"GPIO",
"Low Power",
"ADC",
"SPI"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input"
]
},
{
"numero": "16",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO7",
"FSPID",
"SDIO_DATA1"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control JTAG signal source (see datasheet section 3.4)"
]
},
{
"numero": "17",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO8",
"SDIO_DATA0",
"PAD_COMP0"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "18",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO9",
"SDIO_CLK",
"PAD_COMP1"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "19",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO10",
"FSPICS0",
"SDIO_CMD"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "20",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"After reset, this pin will have internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "21",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO12",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "22",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D-",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"After reset, this pin will be configured as input",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "23",
"nome": "GPIO14",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO14",
"USB_D+",
"SDIO_DATA4"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"During reset, this pin will have internal USB pull-up enabled",
"After reset, this pin will be configured as input with internal USB pull-up enabled",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "24",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"High-performance digital domain and partial analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "25",
"nome": "SPICS1",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO15",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "26",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO16",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "27",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "28",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO18",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "29",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Power output for external flash",
"GPIO19"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details",
"Can only be used as GPIO if external flash memory is powered by an external supply"
]
},
{
"numero": "30",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO20",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "31",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO21",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "32",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO22",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "33",
"nome": "GPIO23",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO23"
],
"categorias": [
"GPIO"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "34",
"nome": "GPIO24",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "35",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO25"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control SDIO Slave timing (see datasheet section 3.4)"
]
},
{
"numero": "36",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO26"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "37",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO27"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input with internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used to control chip boot mode (see datasheet section 3.1)",
"Used to control UART0 ROM message printing (see datasheet section 3.3)"
]
},
{
"numero": "38",
"nome": "GPIO28",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO28"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input with internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "39",
"nome": "VDDPST3",
"tipo": "power",
"funcoes": [
"High-performance digital domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "40",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "41",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "42",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"RF antenna connection for 2 GHz band"
],
"categorias": [
"Antenna"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "43",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
},
{
"numero": "44",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "44",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "45",
"nome": "VDDA5",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "47",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
},
{
"numero": "48",
"nome": "ANT_5G",
"tipo": "analog",
"funcoes": [
"RF antenna connection for 5 GHz band"
],
"categorias": [
"Antenna"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
}
]
+841
View File
@@ -0,0 +1,841 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"RF antenna connection"
],
"categorias": [
"Antenna"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Enable chip"
],
"categorias": [
"Power"
],
"avisos": [
"Pulling this pin high enables chip operation",
"Pulling this pin low disables chip operation",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Low-power digital domain and partial analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "6",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
]
},
{
"numero": "7",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
]
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input"
]
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input"
]
},
{
"numero": "10",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Pin used for debugging",
"Used to control SDIO Slave timing (see datasheet section 3.2)"
]
},
{
"numero": "11",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH5",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Pin used for debugging",
"Used to control SDIO Slave timing (see datasheet section 3.2)"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"LP_GDIO6",
"LP_I2C_SDA",
"ADC1_CH6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"I2C_SDA function is available in low-power (LP) mode",
"Pin used for debugging"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO7",
"LP_GDIO7",
"LP_I2C_SCL",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"SPI",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"I2C_SDA function is available in low-power (LP) mode",
"Pin used for debugging"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control chip boot mode (see datasheet section 3.1)",
"Used to control UART0 ROM message printing (see datasheet section 3.3)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input with internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO10"
],
"categorias": [
"GPIO"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "17",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO11"
],
"categorias": [
"GPIO"
],
"avisos": [
"After reset, this pin will be configured as input"
]
},
{
"numero": "18",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"After reset, this pin will be configured as input",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "19",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "20",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO24",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "21",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO25",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "22",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO26",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "23",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Power supply input/output for flash memory",
"GPIO27"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details",
"Can only be used as GPIO if external flash memory is powered by an external supply"
]
},
{
"numero": "24",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO28",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "25",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO29",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "26",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO30",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used by SPI flash memory",
"Not recommended to use this pin as GPIO"
]
},
{
"numero": "27",
"nome": "GPIO15",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO15"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control JTAG signal source (see datasheet section 3.4)"
]
},
{
"numero": "28",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"High-performance digital domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "29",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO16",
"U0TXD",
"FSPICS0"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"After reset, this pin will have internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "30",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO17",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "31",
"nome": "SDIO_CMD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO18",
"SDIO_CMD",
"FSPICS2"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "32",
"nome": "SDIO_CLK",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO19",
"SDIO_CLK",
"FSPICS3"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "33",
"nome": "SDIO_DATA0",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO20",
"SDIO_DATA0",
"FSPICS4"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "34",
"nome": "SDIO_DATA1",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO21",
"SDIO_DATA1",
"FSPICS5"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "35",
"nome": "SDIO_DATA2",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22",
"SDIO_DATA2"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "36",
"nome": "SDIO_DATA3",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"During reset, this pin will have internal pull-up enabled",
"After reset, this pin will be configured as input"
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negative clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positive clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "41",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
}
]
+729
View File
@@ -0,0 +1,729 @@
[
{
"numero": "1",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"RF antenna connection (Wi-Fi and Bluetooth)"
],
"categorias": [
"Antenna",
"RF"
],
"avisos": [
"Dedicated 2.4 GHz RF pin. Requires 50-ohm impedance matching."
]
},
{
"numero": "2",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"3.3V analog domain power supply"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V (3.0V to 3.6V). Supplies power to RF and clock circuits."
]
},
{
"numero": "3",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"3.3V analog domain power supply"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V (3.0V to 3.6V). Supplies power to RF and clock circuits."
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Enable chip (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Active High. Pull high to enable chip boot.",
"Do not leave this pin floating. An external RC circuit is recommended for clean reset."
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Digital power supply for HP (High Performance) and LP (Low Power) domains"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V. Powers low-power digital circuitry and associated pins."
]
},
{
"numero": "6",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
],
"avisos": [
"Low-power multifunction pin. Can connect to external 32 kHz crystal (Input P)."
]
},
{
"numero": "7",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
],
"avisos": [
"Multifunction pin. External 32 kHz crystal connection (Output N) and ADC1 Channel 0 analog input."
]
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2"
],
"categorias": [
"GPIO"
]
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"MTMS",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Multifunction pin: JTAG MTMS, ADC1 Channel 1, and Strapping pin for SDIO clock edge control.",
"Floating by default during reset."
]
},
{
"numero": "10",
"nome": "GPIO4",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"MTDI",
"ADC1_CH2"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Multifunction pin: JTAG MTDI, ADC1 Channel 2, and Strapping pin for SDIO clock edge control.",
"Floating by default during reset."
]
},
{
"numero": "11",
"nome": "GPIO5",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"MTCK",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"JTAG",
"ADC"
],
"avisos": [
"Multifunction pin: JTAG MTCK and ADC1 Channel 3 analog input."
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"MTDO"
],
"categorias": [
"GPIO",
"JTAG"
],
"avisos": [
"Multifunction pin: JTAG MTDO."
]
},
{
"numero": "13",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO25",
"SDIO_CMD",
"FSPICS0"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Command or SPI2 Chip Select 0."
]
},
{
"numero": "14",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO26",
"SDIO_CLK",
"FSPICLK"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Clock or SPI2 Clock."
]
},
{
"numero": "15",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO27",
"SDIO_DATA0",
"FSPID"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed multifunction pin: SDIO Data 0 or SPI2 MOSI (FSPID)."
]
},
{
"numero": "16",
"nome": "GPIO28",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO28",
"SDIO_DATA1",
"FSPIQ"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 1 or SPI2 MISO (FSPIQ)."
]
},
{
"numero": "17",
"nome": "GPIO22",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22",
"SDIO_DATA2",
"FSPIWP"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 2 or SPI2 Write Protect."
]
},
{
"numero": "18",
"nome": "GPIO23",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"SDIO_DATA3",
"FSPIHD"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"High-speed pin: SDIO Data 3 or SPI2 Hold."
]
},
{
"numero": "19",
"nome": "GPIO14",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO14",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Dedicated Chip Select 1 pin for SPI Flash/PSRAM memory interface."
]
},
{
"numero": "20",
"nome": "GPIO15",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO15",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Dedicated Chip Select 0 pin for SPI Flash memory interface."
]
},
{
"numero": "21",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"HP (High Performance) digital domain power supply"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended voltage: 3.3V (3.0V to 3.6V). Powers high-speed digital interfaces."
]
},
{
"numero": "22",
"nome": "GPIO16",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO16",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Data Q (MISO) pin for SPI flash memory interface."
]
},
{
"numero": "23",
"nome": "GPIO17",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO17",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Write Protect pin for SPI flash memory interface."
]
},
{
"numero": "24",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"LDO output voltage generated from VDDPST2 to power Flash and PSRAM"
],
"categorias": [
"Power"
],
"avisos": [
"Software-configurable output voltage matching internal/external flash specs (typically 3.3V or 1.8V).",
"Must not be used as a general high-current power source."
]
},
{
"numero": "25",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO19",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Hold control pin for SPI flash memory interface."
]
},
{
"numero": "26",
"nome": "GPIO20",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO20",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Clock signal pin for SPI flash memory interface."
]
},
{
"numero": "27",
"nome": "GPIO21",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO21",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Data D (MOSI) pin for SPI flash memory interface."
]
},
{
"numero": "28",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Negative signal pin of integrated USB Serial/JTAG transceiver."
]
},
{
"numero": "29",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Positive signal pin of integrated USB Serial/JTAG transceiver.",
"Equipped with integrated pull-up enabled by default during USB initialization."
]
},
{
"numero": "30",
"nome": "GPIO24",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
]
},
{
"numero": "31",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping pin for boot mode selection and ROM log printing control.",
"Floating by default during reset. High level (1) enables boot log printing."
]
},
{
"numero": "32",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Primary Strapping pin for boot mode selection.",
"Equipped with integrated weak pull-up. High level (1) at reset enables SPI Boot (loads from flash). Low level (0) forces Download mode."
]
},
{
"numero": "33",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO10",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 serial reception (Serial RX for firmware flashing and debugging)."
]
},
{
"numero": "34",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"UART0 serial transmission (Serial TX for external firmware flashing and debugging)."
]
},
{
"numero": "35",
"nome": "GPIO29",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO29"
],
"categorias": [
"GPIO"
]
},
{
"numero": "36",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO7"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Strapping pin for JTAG signal source selection (early boot).",
"No internal pull resistors at reset. Must be kept stable by external circuitry if used."
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"3.3V analog domain power supply"
],
"categorias": [
"Power"
]
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"External 40 MHz crystal oscillator connection (Output N)"
],
"categorias": [
"Clock"
]
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"External 40 MHz crystal oscillator connection (Input P)"
],
"categorias": [
"Clock"
]
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"3.3V analog domain power supply"
],
"categorias": [
"Power"
]
},
{
"numero": "41",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Center ground pad (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Must be properly soldered to the PCB ground plane (GND) for stable RF and thermal performance."
]
}
]
+603
View File
@@ -0,0 +1,603 @@
[
{
"numero": "1",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "3",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"FSPIQ"
],
"categorias": [
"GPIO",
"SPI"
]
},
{
"numero": "4",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"FSPICS0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"SPI",
"ADC"
]
},
{
"numero": "5",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"FSPIWP",
"ADC1_CH1",
"MTMS"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "6",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"FSPIHD",
"ADC1_CH2",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "7",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"FSPICLK",
"ADC1_CH3",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "8",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"FSPID",
"ADC1_CH4",
"MTDI"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"After reset, this pin will be configured as input",
"Pin used for debugging"
]
},
{
"numero": "9",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"I/O domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "10",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control chip boot mode (see datasheet section 3.1)",
"Used to control UART0 ROM message printing (see datasheet section 3.3)"
]
},
{
"numero": "11",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input with internal pull-up enabled",
"After reset, this pin will be configured as input with internal pull-up enabled",
"Used to control chip boot mode (see datasheet section 3.1)"
]
},
{
"numero": "12",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO10",
"ZCD0"
],
"categorias": [
"GPIO"
]
},
{
"numero": "13",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO11",
"ZCD1"
],
"categorias": [
"GPIO"
]
},
{
"numero": "14",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO12"
],
"categorias": [
"GPIO"
]
},
{
"numero": "15",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO13",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
]
},
{
"numero": "16",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO14",
"XTAL_32K_N"
],
"categorias": [
"GPIO",
"Clock"
]
},
{
"numero": "17",
"nome": "CHIP_EN",
"tipo": "analog",
"alimentacao": [
"VBAT"
],
"funcoes": [
"Enable chip"
],
"categorias": [
"Power"
],
"avisos": [
"Pulling this pin high enables chip operation",
"Pulling this pin low disables chip operation",
"Do not leave this pin floating, use an external pull-up resistor"
]
},
{
"numero": "18",
"nome": "VBAT",
"tipo": "power",
"funcoes": [
"Analog domain or battery power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "19",
"nome": "VDDA_PMU",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "20",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"I/O domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "21",
"nome": "GPIO22",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22"
],
"categorias": [
"GPIO"
]
},
{
"numero": "22",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "23",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24",
"U0TXD",
"FSPICS2"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"After reset, this pin will be configured as input with internal pull-up enabled",
"Pin used for debugging"
]
},
{
"numero": "24",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24",
"FSPICS3"
],
"categorias": [
"GPIO",
"SPI",
"Strapping"
],
"avisos": [
"During reset, this pin will be configured as input",
"After reset, this pin will be configured as input",
"Used to control JTAG signal source (see datasheet section 3.3)"
]
},
{
"numero": "25",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO26",
"FSPICS4",
"USB_D-"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"After reset, this pin will be configured as input",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "26",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO27",
"FSPICS5",
"USB_D+"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"After reset, this pin will be configured as input with internal USB pull-up enabled",
"By default, this pin is used for USB Serial/JTAG"
]
},
{
"numero": "27",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "28",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Negative clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.2 for analog pin details"
]
},
{
"numero": "29",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Positive clock input/output"
],
"categorias": [
"Clock"
],
"avisos": [
"See datasheet section 2.3.2 for analog pin details"
]
},
{
"numero": "30",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "31",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Analog domain power supply input"
],
"categorias": [
"Power"
],
"avisos": [
"Recommended Voltage: 3.3V",
"Minimum Recommended Voltage: 3.0V",
"Maximum Recommended Voltage: 3.6V",
"See datasheet section 2.5 for chip power supply details"
]
},
{
"numero": "32",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"RF antenna connection"
],
"categorias": [
"Antenna"
],
"avisos": [
"Refer to datasheet section 2.4 for more details on analog pins"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Circuit electrical ground reference (GND)"
],
"categorias": [
"GND"
]
}
]
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+391
View File
@@ -0,0 +1,391 @@
{
"ESP-IDF": {
"nome": "ESP-IDF",
"icone": "⚙️",
"nome_completo": "Espressif IoT Development Framework",
"descricao": "Official native Espressif framework for all ESP32 SoCs. Based on multicore FreeRTOS and CMake, providing full control over silicon, peripherals, radio, and modular component architecture.",
"linguagem": "C / C++",
"tipo": "Official Base Framework",
"funcao_principal": "Industrial and high-performance development with direct register access, real-time RTOS, and complete protocol stack",
"caracteristicas": [
"Real-time operating system (FreeRTOS SMP multicore)",
"Native support for ESP Component Registry via idf_component.yml",
"Full connectivity stack for Wi-Fi 4/6, BLE 5.x, Zigbee and Thread",
"Support for all SoCs (ESP32, S2, S3, C2, C3, C6, H2, P4)",
"Advanced power management and Deep Sleep modes",
"Robust security: Secure Boot v2, Flash Encryption and Hardware Crypto",
"Encrypted OTA updates with automatic rollback",
"Modern Clang/GCC toolchain, C++23 support and JTAG OpenOCD debugging"
],
"casos_uso": [
"Commercial and industrial IoT products",
"Devices with strict battery and low-power requirements",
"Real-time applications with precise interrupt control",
"Security systems with hardware encryption",
"High-performance multiprotocol gateways"
],
"exemplo": "/exemplos/esp-idf.c",
"exemplos": "https://github.com/espressif/esp-idf/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-idf/en/latest/",
"repositorio": "https://github.com/espressif/esp-idf",
"cor": "#E74C3C"
},
"ESP-RainMaker": {
"nome": "ESP-RainMaker",
"icone": "☁️",
"nome_completo": "ESP RainMaker AIoT Cloud Platform",
"descricao": "Complete cloud and firmware platform from Espressif for connected products. Build IoT devices without developing backend or mobile apps from scratch.",
"linguagem": "C / C++",
"tipo": "Cloud & AIoT Framework",
"funcao_principal": "Accelerated smart product development with mobile apps (iOS/Android), AWS Serverless cloud and voice control (Alexa/Google Home)",
"caracteristicas": [
"Assisted Wi-Fi and BLE provisioning via official mobile app",
"Dynamic UI generation in app based on firmware parameters",
"Native integration with Alexa and Google Assistant",
"Simultaneous local control (via mDNS/HTTP) and cloud control",
"RainMaker Dashboard for fleet management and OTA",
"Native compatibility with Matter nodes and device Bridges",
"Integrated library via ESP Component Registry (espressif/esp_rainmaker)"
],
"casos_uso": [
"Smart appliances and consumer lighting",
"IoT products with tight time-to-market constraints",
"Devices requiring mobile app control without custom backend costs",
"Remote monitoring systems with centralized OTA"
],
"exemplo": "/exemplos/esp-rainmaker.c",
"exemplos": "https://github.com/espressif/esp-rainmaker/tree/master/examples",
"documentacao": "https://rainmaker.espressif.com/docs/",
"repositorio": "https://github.com/espressif/esp-rainmaker",
"cor": "#3B82F6"
},
"ESP-Matter": {
"nome": "ESP-Matter",
"icone": "🏠",
"nome_completo": "ESP Matter SDK",
"descricao": "Official Espressif SDK for the Matter smart home standard (formerly Project CHIP). Enables interoperability across Apple HomeKit, Google Home, Alexa, and Home Assistant.",
"linguagem": "C++",
"tipo": "Smart Home Framework",
"funcao_principal": "Development of smart devices and bridges compliant with the unified Matter standard over Wi-Fi and Thread",
"caracteristicas": [
"Full implementation of Matter specification clusters",
"Transport support over Wi-Fi and Thread (802.15.4 on ESP32-H2 and ESP32-C6)",
"Simplified commissioning via BLE or On-Network",
"Simultaneous compatibility with Apple Home, Google Home, Alexa and SmartThings",
"Security based on Device Attestation Certificates (DAC)",
"Matter Bridge support (bridging legacy Zigbee/BLE devices into Matter)",
"Direct integration with ESP-IDF and ESP Component Registry"
],
"casos_uso": [
"Interoperable smart bulbs, plugs, switches and dimmers",
"Presence, temperature, humidity and contact sensors",
"Electronic locks and window blind actuators",
"Residential Matter Border Routers and Bridges"
],
"exemplo": "/exemplos/esp-matter.c",
"exemplos": "https://github.com/espressif/esp-matter/tree/main/examples",
"documentacao": "https://docs.espressif.com/projects/esp-matter/en/latest/",
"repositorio": "https://github.com/espressif/esp-matter",
"cor": "#F59E0B"
},
"ESP-ADF": {
"nome": "ESP-ADF",
"icone": "🎵",
"nome_completo": "ESP Audio Development Framework",
"descricao": "Specialized framework for high-quality digital audio processing, streaming, and playback on ESP32 SoCs.",
"linguagem": "C / C++",
"tipo": "Audio & Voice Framework",
"funcao_principal": "Creation of flexible audio pipelines with decoders, network streaming, equalization and acoustic effects",
"caracteristicas": [
"Modular audio pipeline architecture (Audio Elements & Audio Stream)",
"Multi-codec support: MP3, AAC, FLAC, WAV, OGG, Opus and AMR",
"Audio streaming over HTTP, HTTPS, HLS, RTSP and WebSockets",
"Bluetooth A2DP (Sink/Source) and Bluetooth Handsfree (HFP) support",
"Acoustic processing algorithms (AEC, AGC, NS, parametric equalizers)",
"Support for dedicated audio boards such as ESP32-LyraT and ESP32-S3-Korvo"
],
"casos_uso": [
"Smart speakers and internet radio receivers",
"Intercoms, walkie-talkies and VoIP systems",
"Music playback players with PSRAM",
"Building automation background audio systems"
],
"exemplo": "/exemplos/esp-adf.c",
"exemplos": "https://github.com/espressif/esp-adf/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-adf/en/latest/",
"repositorio": "https://github.com/espressif/esp-adf",
"cor": "#0284C7"
},
"ESP-SR": {
"nome": "ESP-SR",
"icone": "🎙️",
"nome_completo": "ESP Speech Recognition Framework",
"descricao": "Local speech recognition and edge AI audio processing framework, enabling offline voice commands without internet connection.",
"linguagem": "C / C++",
"tipo": "Voice & AI Framework",
"funcao_principal": "Offline voice control with wake word detection, localized command speech-to-intent and acoustic front-end (AFE)",
"caracteristicas": [
"WakeNet: high-accuracy wake word engine (e.g., 'Hi ESP', 'Alexa')",
"MultiNet: offline speech command recognition for multiple languages",
"Acoustic Front-End (AFE): noise suppression, beamforming and echo cancellation (AEC)",
"Hardware acceleration on ESP32-S3 via Xtensa vector instructions",
"Zero cloud latency and complete user voice privacy"
],
"casos_uso": [
"Offline voice-controlled home appliances",
"Industrial voice terminals in noisy environments",
"Privacy-focused smart home gadgets",
"Interactive toys and hands-free assistive devices"
],
"exemplo": "/exemplos/esp-sr.c",
"exemplos": "https://github.com/espressif/esp-sr/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-sr/en/latest/",
"repositorio": "https://github.com/espressif/esp-sr",
"cor": "#6366F1"
},
"ESP-IoT-Solution": {
"nome": "ESP-IoT-Solution",
"icone": "🧩",
"nome_completo": "ESP-IoT-Solution Driver & Peripheral Suite",
"descricao": "Collection of drivers, peripheral libraries and hardware solutions for ESP32 and ESP-IDF.",
"linguagem": "C / C++",
"tipo": "Peripheral Library & Drivers",
"funcao_principal": "Modular peripheral drivers for displays, touch, sensors, audio DACs and power management",
"caracteristicas": [
"Drivers for OLED, TFT, e-Paper displays and LED matrices",
"Support for environmental, motion and power sensors",
"Touch sensing algorithms and gesture recognition",
"USB host and device class implementations",
"Modular integration via ESP Component Registry"
],
"casos_uso": [
"Smart screens and HMI interfaces",
"Sensor hubs and data loggers",
"Battery-powered portable gadgets",
"Custom peripheral prototyping"
],
"exemplo": "/exemplos/esp-iot-solution.c",
"exemplos": "https://github.com/espressif/esp-iot-solution/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-iot-solution/en/latest/",
"repositorio": "https://github.com/espressif/esp-iot-solution",
"cor": "#10B981"
},
"ESP-NOW": {
"nome": "ESP-NOW & Mesh",
"icone": "📡",
"nome_completo": "ESP-NOW Protocol & Mesh-Lite",
"descricao": "Connectionless, ultra-fast wireless protocol developed by Espressif for short-packet peer-to-peer communication.",
"linguagem": "C / C++",
"tipo": "Network Protocol & Mesh",
"funcao_principal": "Ultra-low-latency, low-overhead communication between ESP devices without a Wi-Fi router",
"caracteristicas": [
"Fast peer-to-peer communication without Wi-Fi association",
"Sub-millisecond packet latency",
"Low energy consumption, ideal for battery sensors",
"Payload up to 250 bytes with optional AES-128 encryption",
"Supports one-to-many and many-to-one topologies"
],
"casos_uso": [
"Remote controls and wireless buttons",
"Battery-powered sensor nodes",
"Low-latency smart home triggers",
"Industrial point-to-point telemetry"
],
"exemplo": "/exemplos/esp-now.c",
"exemplos": "https://github.com/espressif/esp-now/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html",
"repositorio": "https://github.com/espressif/esp-now",
"cor": "#8B5CF6"
},
"ESP-Zigbee-SDK": {
"nome": "ESP-Zigbee-SDK",
"icone": "🐝",
"nome_completo": "ESP Zigbee SDK (ZCL & ZBOSS)",
"descricao": "Official Zigbee 3.0 SDK for IEEE 802.15.4-capable ESP32 SoCs (ESP32-H2 and ESP32-C6).",
"linguagem": "C / C++",
"tipo": "Smart Home & Mesh",
"funcao_principal": "Building standard Zigbee 3.0 devices including Coordinators, Routers and End Devices",
"caracteristicas": [
"Certified Zigbee 3.0 protocol stack (ZCL, BDB)",
"Support for Zigbee Coordinator, Router and Sleepy End Device roles",
"Native IEEE 802.15.4 hardware radio on ESP32-H2 and ESP32-C6",
"Interoperable with commercial Zigbee ecosystems (Philips Hue, Tuya, Zigbee2MQTT)",
"OTA cluster support for Zigbee firmware updates"
],
"casos_uso": [
"Zigbee home automation sensors and actuators",
"Zigbee to Wi-Fi/Ethernet gateway hubs",
"Low-power sleepy sensor nodes",
"Commercial lighting networks"
],
"exemplo": "/exemplos/esp-zigbee.c",
"exemplos": "https://github.com/espressif/esp-zigbee-sdk/tree/main/examples",
"documentacao": "https://docs.espressif.com/projects/esp-zigbee-sdk/en/latest/",
"repositorio": "https://github.com/espressif/esp-zigbee-sdk",
"cor": "#EC4899"
},
"ESP-WHO": {
"nome": "ESP-WHO",
"icone": "📷",
"nome_completo": "ESP Image Processing & Vision Framework",
"descricao": "Computer vision and image recognition framework designed for ESP32-S3 and ESP32-CAM devices.",
"linguagem": "C / C++",
"tipo": "Computer Vision & AI",
"funcao_principal": "Face detection, face recognition, human presence and cat/dog detection on microcontrollers",
"caracteristicas": [
"Optimized neural networks for Xtensa LX7 and vector instructions",
"Face detection and recognition pipelines",
"Support for DVP and MIPI-CSI camera sensors (OV2640, OV3660, OV5640)",
"Works with PSRAM for image buffering and tensor storage",
"Real-time processing directly on device"
],
"casos_uso": [
"Smart video doorbells and access control",
"Human presence detection for energy saving",
"Edge camera monitoring systems",
"Vision-guided robotics"
],
"exemplo": "/exemplos/esp-who.c",
"exemplos": "https://github.com/espressif/esp-who/tree/master/examples",
"documentacao": "https://github.com/espressif/esp-who",
"repositorio": "https://github.com/espressif/esp-who",
"cor": "#F97316"
},
"ESP-NN": {
"nome": "ESP-NN",
"icone": "🧠",
"nome_completo": "ESP Neural Network Acceleration Library",
"descricao": "Neural network acceleration library optimized specifically for ESP32 architectures.",
"linguagem": "C / C++",
"tipo": "Specialized AI Library",
"funcao_principal": "Hardware-accelerated kernel execution for machine learning inference at the edge (TinyML)",
"caracteristicas": [
"Official accelerator backend for TensorFlow Lite for Microcontrollers (TFLM)",
"Efficient 8-bit and 16-bit quantization to minimize RAM and Flash usage",
"SIMD vector instructions acceleration on ESP32-S3 and ESP32-P4",
"Zero RTOS overhead for critical inference kernels",
"Fully open source and maintainable"
],
"casos_uso": [
"Audio classification and vibration analysis (predictive maintenance)",
"Anomaly detection on industrial sensor streams",
"IMU gesture recognition",
"Ultralight vision models on microcontrollers"
],
"exemplo": "/exemplos/esp-nn.c",
"exemplos": "https://github.com/espressif/esp-nn/tree/master/test_app",
"documentacao": "https://github.com/espressif/esp-nn",
"repositorio": "https://github.com/espressif/esp-nn",
"cor": "#14B8A6"
},
"ESP-DSP": {
"nome": "ESP-DSP",
"icone": "📊",
"nome_completo": "ESP Digital Signal Processing Library",
"descricao": "Official digital signal processing library for the ESP32 family, providing hardware-accelerated math routines.",
"linguagem": "C / C++",
"tipo": "Specialized Signal Processing Library",
"funcao_principal": "High-speed execution of intensive mathematical algorithms including FFT, matrix operations and digital filtering",
"caracteristicas": [
"Fast Fourier Transforms (Real and Complex FFT) optimized in Assembly",
"Digital filters (IIR, FIR) and Kalman filter estimators",
"Matrix, vector and dot product operations",
"Floating-point and fixed-point support (Radix-2 and Radix-4)",
"Custom optimizations for Xtensa Dual-Core and RISC-V architectures"
],
"casos_uso": [
"Real-time audio and vibration spectral analysis",
"Noise reduction filters for biomedical and industrial sensors",
"High-precision motor control and FOC algorithms",
"Edge data compression and encoding"
],
"exemplo": "/exemplos/esp-dsp.c",
"exemplos": "https://github.com/espressif/esp-dsp/tree/master/examples",
"documentacao": "https://docs.espressif.com/projects/esp-dsp/en/latest/",
"repositorio": "https://github.com/espressif/esp-dsp",
"cor": "#A855F7"
},
"Rust-ESP": {
"nome": "Rust on ESP32",
"icone": "🦀",
"nome_completo": "ESP-RS Rust Ecosystem for ESP32",
"descricao": "Modern Rust language development ecosystem for the ESP32 family, combining memory safety, robust concurrency, and high performance.",
"linguagem": "Rust",
"tipo": "Modern Language & Framework",
"funcao_principal": "Safe, high-performance firmware development in both bare-metal mode (no_std via esp-hal) and full stack (std via esp-idf-svc)",
"caracteristicas": [
"Bare-metal no_std mode with esp-hal: full control without RTOS and ultra-fast boot",
"Standard std mode with esp-idf-svc: access to Rust standard library, Wi-Fi, BLE, HTTP, MQTT and threads",
"Compile-time prevention against memory corruption and data races",
"Target support for Xtensa (ESP32, S2, S3) and native RISC-V (C2, C3, C6, H2, P4)",
"Integration with embedded-hal ecosystem and async/await via embassy",
"Official tooling: espflash for flashing and serial monitoring, esp-generate for project templates"
],
"casos_uso": [
"Mission-critical systems where memory safety errors are unacceptable",
"Modern IoT applications with clean asynchronous concurrency",
"Industrial devices requiring high reliability and security",
"Modern robotics and instrumentation projects"
],
"exemplo": "/exemplos/rust-esp.rs",
"exemplos": "https://github.com/esp-rs/esp-hal/tree/main/examples",
"documentacao": "https://esp-rs.github.io/book/",
"repositorio": "https://github.com/esp-rs",
"cor": "#E44D26"
},
"Arduino": {
"nome": "Arduino Core",
"icone": "🛠️",
"nome_completo": "Arduino Core for ESP32",
"descricao": "Official Arduino core implementation running on top of ESP-IDF (v3.x+ based on ESP-IDF v5.1+), combining maximum ease of use with ESP32 advanced features.",
"linguagem": "C++",
"tipo": "Popular Alternative Framework",
"funcao_principal": "Rapid prototyping, education and fast development leveraging the vast Arduino library ecosystem",
"caracteristicas": [
"Classic setup() and loop() syntax with hundreds of thousands of compatible libraries",
"Runs as a FreeRTOS task on top of official ESP-IDF",
"Full support for Wi-Fi, Bluetooth Classic/BLE, WebServer and WebSockets",
"Compatible with Arduino IDE 2.x, PlatformIO and VS Code",
"Updated support for all popular SoCs (ESP32, S2, S3, C3, C6)",
"Direct access to underlying ESP-IDF APIs when needed"
],
"casos_uso": [
"Rapid prototyping and proof-of-concept (PoC) validation",
"Educational, maker and academic projects",
"Simple IoT systems with dashboards (Blynk, Adafruit IO, ThingSpeak)",
"DIY home automation and hobbyist robotics"
],
"exemplo": "/exemplos/arduino.ino",
"exemplos": "https://github.com/espressif/arduino-esp32/tree/master/docs/en/tutorials",
"documentacao": "https://docs.espressif.com/projects/arduino-esp32/en/latest/",
"repositorio": "https://github.com/espressif/arduino-esp32",
"cor": "#00979D"
},
"MicroPython": {
"nome": "MicroPython",
"icone": "🐍",
"nome_completo": "MicroPython for ESP32",
"descricao": "Lean and efficient implementation of Python 3 optimized to run directly on ESP32 microcontrollers with a real-time interpreter.",
"linguagem": "Python",
"tipo": "Language & Dynamic Interpreter",
"funcao_principal": "Interactive development and rapid Python prototyping with an interactive REPL console and direct hardware control",
"caracteristicas": [
"Full Python 3 interpreter compiling directly to RAM bytecode",
"Interactive REPL console over serial and WebREPL over Wi-Fi",
"Built-in filesystem (LittleFS / FAT) with .py script uploads without recompilation",
"Native modules: machine, network, bluetooth, espnow and asyncio",
"Ideal for teaching physical computing and embedded algorithms on real hardware"
],
"casos_uso": [
"Teaching physical computing and university laboratory courses",
"Rapid prototyping and fast sensor testing on the workbench",
"Automated hardware test bench scripts",
"Experimental IoT data collection applications"
],
"exemplo": "/exemplos/micropython.py",
"exemplos": "https://github.com/micropython/micropython/tree/master/examples",
"documentacao": "https://docs.micropython.org/en/latest/esp32/",
"repositorio": "https://github.com/micropython/micropython",
"cor": "#2B2B2B"
}
}
+732
View File
@@ -0,0 +1,732 @@
{
"ESP32": {
"nome_completo": "ESP32 (Classic)",
"icone": "🔷",
"descricao": "The original model with dual-core processor and wide range of peripherals",
"arquitetura": "Xtensa® LX6 dual-core 32-bit",
"nucleos": "1 (Single-core) or 2 (Dual-core)",
"frequencia": "Up to 240 MHz",
"coprocessador_ulp": "Yes",
"seguranca": {
"aes": "AES-128/192/256",
"sha": "SHA-1/256/384/512",
"rsa": "Yes (RSA/MPI up to 4096 bits)",
"ecc": "No",
"ecdsa": "No",
"hmac": "No",
"assinatura_digital": "No",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "Yes (AES-256, legacy scheme)",
"secure_boot": "V1 (AES, legacy); V2 (RSA-3072, RSA-PSS) starting from rev v3.0 (ECO3)",
"protecao_dpa": "No"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, up to 150 Mbps)",
"bluetooth": "Bluetooth 4.2 BR/EDR (Classic) and Bluetooth LE (dual mode)",
"ethernet": "Yes (Integrated Ethernet MAC)",
"memoria_sram": "520 KB",
"memoria_sram_rtc": "16 KB (divided into RTC FAST and RTC SLOW)",
"memoria_rom": "448 KB (for boot and core functions)",
"flash_externa": "Up to 16 MB via QSPI",
"psram_externa": "Up to 8 MB via QSPI (in specific modules such as WROVER)",
"gpio": "34",
"adc": "2x 12-bit SAR ADC, up to 18 channels",
"dac": "2x 8-bit DAC",
"touch": "10 capacitive channels",
"uart": "3",
"spi": "4 (SPI, HSPI, VSPI - 2 can be used for Flash/PSRAM)",
"i2c": "2",
"i2s": "2",
"pwm": "LED PWM (up to 16 channels), Motor PWM",
"ethernet_mac": "1 (requires external PHY)",
"can": "1 (CAN 2.0, TWAI®)",
"sdio": "1 (SD/SDIO/MMC Host), 1 (SDIO/SPI Slave)",
"sensor_hall": "1 (internal)",
"sensor_temperatura": "No (removed from datasheet in 2018; no driver in ESP-IDF)",
"consumo_energia": {
"active_cpu_240mhz": "30-68 mA",
"active_wifi_tx": "180-240 mA",
"modem_sleep": "20-44 mA",
"light_sleep": "0.8 mA",
"deep_sleep": "10-150 µA",
"hibernation": "5 µA"
},
"temperatura_operacao": "-40°C to 125°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "External JTAG (requires probe, e.g. ESP-PROG)",
"esp_idf_minimo": "Since initial release (v3.x and earlier)",
"arduino_core": "Yes (147 board definitions in official core)",
"encapsulamento": "QFN48 (6×6 mm) and QFN48 (5×5 mm)",
"modulos": "ESP32-MINI-1, ESP32-PICO-MINI-02, ESP32-PICO-V3, ESP32-PICO-V3-02 and 11 more",
"datasheet": "https://documentation.espressif.com/esp32_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html",
"placa": "/placas/esp32.png",
"cor": "#007bff"
},
"ESP32-S2": {
"nome_completo": "ESP32-S2",
"icone": "🔒",
"descricao": "Focused on security and low power, with native USB and the only ADC with 13-bit output",
"arquitetura": "Xtensa® LX7 single-core 32-bit",
"nucleos": "1 (Single-core)",
"frequencia": "Up to 240 MHz",
"coprocessador_ulp": "Yes (RISC-V)",
"seguranca": {
"aes": "AES-128/192/256 with GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Yes (RSA/MPI up to 4096 bits)",
"ecc": "No",
"ecdsa": "No",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "No"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, up to 150 Mbps)",
"bluetooth": "No",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "128 KB",
"flash_externa": "Up to 1 GB via QSPI",
"psram_externa": "Up to 1 GB via QSPI/Octal SPI",
"gpio": "43",
"adc": "2x SAR ADC, up to 20 channels: 13-bit output (0–8191, unique in family), 12-bit effective resolution starting from rev v1.0 (errata ADC-112)",
"dac": "2x 8-bit DAC",
"touch": "14 capacitive channels",
"uart": "2",
"spi": "4 (SPI0/1 for Flash, SPI2/3 for general use)",
"i2c": "2",
"i2s": "1",
"pwm": "LED PWM (up to 8 channels)",
"usb": "1 (USB OTG 1.1 Full-Speed)",
"lcd": "8/16-bit LCD interface",
"camera": "8/16-bit DVP interface",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active_wifi_tx": "160-310 mA",
"modem_sleep_cpu_160mhz": "14-24 mA",
"light_sleep": "750 µA",
"deep_sleep": "20-190 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "External JTAG (requires probe, e.g. ESP-PROG)",
"esp_idf_minimo": "v4.2",
"arduino_core": "Yes (26 board definitions in official core)",
"encapsulamento": "QFN56 (7×7 mm)",
"modulos": "ESP32-S2-MINI-1, ESP32-S2-MINI-2, ESP32-S2-SOLO, ESP32-S2-SOLO-2 and 4 more",
"datasheet": "https://documentation.espressif.com/esp32-s2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html",
"placa": "/placas/esp32-s2.png",
"cor": "#28a745"
},
"ESP32-S3": {
"nome_completo": "ESP32-S3",
"icone": "🤖",
"descricao": "Dual-core processor with accelerators for AI and signal processing",
"arquitetura": "Xtensa® LX7 dual-core 32-bit",
"nucleos": "2 (Dual-core)",
"frequencia": "Up to 240 MHz",
"coprocessador_ulp": "Yes (RISC-V)",
"aceleradores_ia": "Yes (Vector Instructions for AI)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "Yes (RSA/MPI up to 4096 bits)",
"ecc": "No",
"ecdsa": "No",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "No"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, up to 150 Mbps)",
"bluetooth": "Bluetooth 5 (LE) and Bluetooth Mesh",
"memoria_sram": "512 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "384 KB",
"flash_externa": "Up to 1 GB via QSPI/Octal SPI",
"psram_externa": "Up to 1 GB via QSPI/Octal SPI",
"gpio": "45",
"adc": "2x 12-bit SAR ADC, up to 20 channels",
"dac": "No",
"touch": "14 capacitive channels",
"uart": "3",
"spi": "4 (SPI0/1 for Flash, SPI2/3 for general use)",
"i2c": "2",
"i2s": "2",
"pwm": "LED PWM (up to 8 channels), Motor PWM (6 channels)",
"usb": "1 (USB OTG 1.1 Full-Speed) + 1 (USB Serial/JTAG)",
"lcd": "8/16-bit RGB LCD interface",
"camera": "8/16-bit DVP interface",
"sdio": "1 (SD/SDIO/MMC Host)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "78 mW (~24 mA @3.3V)",
"modem_sleep": "13-42 mA (40-80 MHz, depending on load)",
"light_sleep": "240 µA (+40 to 200 µA from PSRAM)",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C to 65/85/105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v4.4",
"arduino_core": "Yes (158 board definitions in official core)",
"encapsulamento": "QFN56 (7×7 mm)",
"modulos": "ESP32-S3-MINI-1, ESP32-S3-WROOM-1, ESP32-S3-WROOM-2",
"datasheet": "https://documentation.espressif.com/esp32-s3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/get-started/index.html",
"placa": "/placas/esp32-s3.png",
"cor": "#fd7e14"
},
"ESP32-S31": {
"nome_completo": "ESP32-S31",
"icone": "🌀",
"descricao": "High-performance dual-core RISC-V processor at 320 MHz with Wi-Fi 6, Bluetooth 5.4 and Classic, Zigbee/Thread, Matter and AI acceleration",
"arquitetura": "RISC-V dual-core 32-bit (HP) + RISC-V single-core (LP)",
"nucleos": "2 (Dual-core HP) + 1 (Single-core LP)",
"frequencia": "Up to 320 MHz",
"coprocessador_ulp": "Yes (RISC-V, 40 MHz LP CPU)",
"aceleradores_ia": "Yes (Custom AI and DSP extension XespV)",
"seguranca": {
"aes": "AES-128/256 with GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Yes (RSA/MPI up to 4096 bits)",
"ecc": "Yes (P-192, P-256, P-384)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "Yes",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072)",
"protecao_dpa": "Yes"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5.4 LE and Bluetooth Classic",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Yes",
"memoria_sram": "512 KB (HP SRAM)",
"memoria_sram_rtc": "32 KB (LP SRAM)",
"memoria_rom": "320 KB",
"flash_externa": "Up to 256 MB via QSPI",
"psram_externa": "16 MB or 32 MB octal DDR, in-package only (NRV16, NRV32)",
"gpio": "60",
"adc": "2x 12-bit SAR ADC, up to 16 channels",
"dac": "Yes (2x 10-bit DAC and 2x 12-bit DAC)",
"touch": "14 capacitive channels",
"uart": "5 (4 UART + 1 LP UART)",
"spi": "7 (6 SPI + 1 LP SPI)",
"i2c": "3 (2 I2C + 1 LP I2C)",
"i2s": "2",
"pwm": "LED PWM (up to 8 channels), Motor PWM (MCPWM)",
"usb": "1 (USB 2.0 High-Speed OTG and USB Serial/JTAG)",
"can": "Yes (CAN FD Controller)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "Configurable optimized high-performance consumption",
"light_sleep": "0.1-0.8 mA",
"deep_sleep": "Low power with active LP CPU"
},
"temperatura_operacao": "-40°C to 85°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v6.1 in preview; official support starting from v6.1.1",
"arduino_core": "Not yet supported by arduino-esp32 core",
"encapsulamento": "QFN80 (8×8 mm)",
"modulos": "ESP32-S31-WROOM-1, ESP32-S31-WROOM-3",
"datasheet": "https://documentation.espressif.com/esp32-s31_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-s31_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s31/get-started/index.html",
"placa": "/placas/esp32-s31.png",
"cor": "#ff2a5f",
"sdio": "1 (SDIO Host 3.0)"
},
"ESP32-C2": {
"nome_completo": "ESP32-C2 (ESP8684)",
"icone": "🌱",
"descricao": "Ultra-cost-effective and low-power RISC-V microcontroller with Wi-Fi 4 and Bluetooth 5.3 LE",
"arquitetura": "RISC-V single-core 32-bit",
"nucleos": "1 (Single-core)",
"frequencia": "Up to 120 MHz",
"seguranca": {
"aes": "No",
"sha": "SHA-1/224/256",
"rsa": "No",
"ecc": "Yes (P-192, P-256)",
"ecdsa": "No",
"hmac": "No",
"assinatura_digital": "No",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (ECDSA P-192 or P-256)",
"protecao_dpa": "No"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, up to 72.2 Mbps)",
"bluetooth": "Bluetooth 5.3 LE (certified)",
"memoria_sram": "272 KB (16 KB for cache)",
"memoria_sram_rtc": "No",
"memoria_rom": "576 KB",
"flash_externa": "Up to 16 MB via QSPI, but unavailable in retail variants (ESP8684H2X/H4X have 2 MB or 4 MB in package and do not expose flash pins)",
"psram_externa": "No",
"gpio": "14",
"adc": "1x 12-bit SAR ADC, up to 5 channels",
"dac": "No",
"touch": "No",
"uart": "2",
"spi": "3 (SPI0/1 for internal Flash, SPI2 for general use)",
"i2c": "1 (Master-only)",
"i2s": "No",
"pwm": "LED PWM (up to 6 channels)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active_cpu_120mhz": "10.7-15.6 mA (modem-sleep)",
"light_sleep": "140 µA",
"deep_sleep": "5 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "External JTAG (requires probe, e.g. ESP-PROG)",
"esp_idf_minimo": "v5.0",
"arduino_core": "Yes (1 board definition in official core)",
"encapsulamento": "QFN24 (4×4 mm)",
"modulos": "ESP8684-MINI-1, ESP8684-WROOM-01C, ESP8684-WROOM-02C, ESP8684-WROOM-02UC and 5 more",
"datasheet": "https://documentation.espressif.com/esp32-c2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c2/get-started/index.html",
"placa": "/placas/esp32-c2.png",
"cor": "#8c52ff"
},
"ESP32-C3": {
"nome_completo": "ESP32-C3",
"icone": "💎",
"descricao": "Ultra-low-power RISC-V processor",
"arquitetura": "RISC-V single-core 32-bit",
"nucleos": "1 (Single-core)",
"frequencia": "Up to 160 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Yes (RSA/MPI up to 3072 bits)",
"ecc": "No",
"ecdsa": "No",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072), starting from rev v0.3 (ECO3)",
"protecao_dpa": "No"
},
"wifi": "IEEE 802.11 b/g/n (2.4 GHz, up to 150 Mbps)",
"bluetooth": "Bluetooth 5 (LE) and Bluetooth Mesh",
"memoria_sram": "400 KB",
"memoria_sram_rtc": "8 KB",
"memoria_rom": "384 KB",
"flash_externa": "Up to 16 MB via QSPI",
"psram_externa": "No",
"gpio": "22",
"adc": "2x 12-bit SAR ADC, up to 6 channels",
"dac": "No",
"touch": "No",
"uart": "2",
"spi": "3 (SPI0/1 for Flash, SPI2 for general use)",
"i2c": "1",
"i2s": "1",
"pwm": "LED PWM (up to 6 channels)",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active_cpu_160mhz": "20 mA",
"active_wifi_tx_peak": "335 mA",
"modem_sleep_cpu_160mhz": "16-28 mA",
"light_sleep": "130 µA",
"deep_sleep": "5 µA"
},
"temperatura_operacao": "-40°C to 105°C (85°C on ESP32-C3FN4)",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v4.3",
"arduino_core": "Yes (29 board definitions in official core)",
"encapsulamento": "QFN32 (5×5 mm) and QFN28 (4×4 mm)",
"modulos": "ESP32-C3-MINI-1, ESP32-C3-WROOM-02",
"datasheet": "https://documentation.espressif.com/esp32-c3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html",
"placa": "/placas/esp32-c3.png",
"cor": "#20c997"
},
"ESP32-C5": {
"nome_completo": "ESP32-C5",
"icone": "📶",
"descricao": "The first with dual-band Wi-Fi 6 and Bluetooth 6.0 support, equipped with RISC-V CPU and ULP coprocessor",
"arquitetura": "RISC-V single-core 32-bit (HP) + RISC-V single-core (LP)",
"nucleos": "1 (Single-core HP) + 1 (Single-core LP)",
"frequencia": "Up to 240 MHz",
"coprocessador_ulp": "Yes (RISC-V, 48 MHz LP CPU)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "Yes (RSA/MPI up to 3072 bits)",
"ecc": "Yes (P-192, P-256, P-384)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "Yes",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072 or ECDSA P-256/P-384)",
"protecao_dpa": "Yes"
},
"wifi": "Wi-Fi 6 (802.11ax) dual-band 2.4 GHz and 5 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth Core 6.0 certified)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Yes",
"memoria_sram": "384 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "320 KB",
"flash_externa": "Up to 16 MB via QSPI",
"psram_externa": "Yes, via SPI (flash/PSRAM controller with cache)",
"gpio": "29",
"adc": "1x 12-bit SAR ADC, up to 6 channels",
"dac": "No",
"touch": "No",
"uart": "3 (2 UART + 1 LP UART)",
"spi": "3",
"i2c": "2 (1 I2C + 1 LP I2C)",
"i2s": "1",
"pwm": "LED PWM (up to 6 channels), Motor PWM",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active_wifi": "up to 377 mA (TX at 5 GHz)",
"light_sleep": "60-250 µA",
"deep_sleep": "12 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v5.5.2",
"arduino_core": "Yes (10 board definitions in official core)",
"encapsulamento": "QFN48 (6×6 mm)",
"modulos": "ESP32-C5-MINI-1, ESP32-C5-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c5_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c5_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/get-started/index.html",
"placa": "/placas/esp32-c5.png",
"cor": "#6f42c1",
"sdio": "1 (SDIO Slave, starting from rev v1.0)",
"can": "2 (CAN FD)"
},
"ESP32-C6": {
"nome_completo": "ESP32-C6",
"icone": "🌐",
"descricao": "Advanced security features, Wi-Fi 6, Bluetooth 6.0, Zigbee and Thread with Matter support",
"arquitetura": "RISC-V single-core 32-bit (HP) + RISC-V single-core (LP)",
"nucleos": "1 (Single-core HP) + 1 (Single-core LP)",
"frequencia": "Up to 160 MHz",
"coprocessador_ulp": "Yes (RISC-V, 20 MHz LP CPU)",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Yes (RSA/MPI up to 3072 bits)",
"ecc": "Yes (P-192, P-256)",
"ecdsa": "No",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072 or ECDSA)",
"protecao_dpa": "Yes"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth 5.3 certified)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.3)",
"matter": "Yes",
"memoria_sram": "512 KB",
"memoria_sram_rtc": "16 KB",
"memoria_rom": "320 KB",
"flash_externa": "Up to 16 MB via QSPI",
"psram_externa": "No",
"gpio": "30",
"adc": "1x 12-bit SAR ADC, up to 7 channels",
"dac": "No",
"touch": "No",
"uart": "3 (2 UART + 1 LP UART)",
"spi": "3",
"i2c": "2 (1 I2C + 1 LP I2C)",
"i2s": "1",
"pwm": "LED PWM (up to 6 channels), Motor PWM",
"usb": "1 (USB Serial/JTAG)",
"sdio": "1 (SDIO 2.0 Slave)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active_wifi6": "252-354 mA (TX)",
"light_sleep": "35-180 µA",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v5.1",
"arduino_core": "Yes (21 board definitions in official core)",
"encapsulamento": "QFN40 (5×5 mm) and QFN32 (5×5 mm)",
"modulos": "ESP32-C6-MINI-1, ESP32-C6-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c6_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c6_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/get-started/index.html",
"placa": "/placas/esp32-c6.png",
"cor": "#17a2b8"
},
"ESP32-C61": {
"nome_completo": "ESP32-C61",
"icone": "🛰️",
"descricao": "Cost-effective 160 MHz RISC-V microcontroller with Wi-Fi 6, Bluetooth 6.0 LE and in-package Flash/PSRAM support",
"arquitetura": "RISC-V single-core 32-bit",
"nucleos": "1 (Single-core)",
"frequencia": "Up to 160 MHz",
"seguranca": {
"aes": "No",
"sha": "SHA-1/224/256",
"rsa": "No",
"ecc": "Yes (P-192, P-256)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "No",
"assinatura_digital": "No",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (ECDSA)",
"protecao_dpa": "Yes"
},
"wifi": "Wi-Fi 6 (802.11ax) 2.4 GHz",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth Core 6.0 certified)",
"zigbee_thread": "No",
"matter": "Yes (via Wi-Fi)",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "No",
"memoria_rom": "256 KB",
"flash_externa": "Up to 16 MB via QSPI (models with 4 MB or 8 MB integrated in package)",
"psram_externa": "Up to 16 MB via QSPI (models with 2 MB or 8 MB integrated in package)",
"gpio": "30",
"adc": "1x 12-bit SAR ADC, up to 4 channels",
"dac": "No",
"touch": "No",
"uart": "3",
"spi": "3 (2 for Flash/PSRAM, 1 for general use)",
"i2c": "1",
"i2s": "1",
"pwm": "LED PWM (up to 6 channels)",
"usb": "1 (USB Serial/JTAG)",
"sdio": "1 (SDIO 2.0 Slave)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "240-360 mA (TX)",
"light_sleep": "50-200 µA",
"deep_sleep": "10 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v5.5.2",
"arduino_core": "Yes (1 board definition in official core)",
"encapsulamento": "QFN40 (5×5 mm) or LGA40 (5×5 mm)",
"modulos": "ESP32-C61-MINI-1, ESP32-C61-WROOM-1",
"datasheet": "https://documentation.espressif.com/esp32-c61_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-c61_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c61/get-started/index.html",
"placa": "/placas/esp32-c61.png",
"cor": "#0dcaf0"
},
"ESP32-P4": {
"nome_completo": "ESP32-P4",
"icone": "⚡",
"descricao": "High performance with dual-core RISC-V processor at 400 MHz, AI accelerators and rich media interfaces",
"arquitetura": "32-bit RISC-V high-performance (HP) dual-core + low-power (LP) single-core",
"nucleos": "2 (Dual-core HP) + 1 (Single-core LP)",
"frequencia": "Up to 400 MHz (HP, rev v3.x; 360 MHz in v1.x); LP up to 40 MHz",
"coprocessador_ulp": "Yes (RISC-V, 40 MHz LP CPU)",
"aceleradores_ia": "Yes (Vector Instructions, AI accelerators)",
"seguranca": {
"aes": "AES-128/256 with GCM",
"sha": "SHA-1/224/256/384/512",
"rsa": "Yes (RSA/MPI up to 4096 bits)",
"ecc": "Yes (P-192, P-256, P-384)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "Yes",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "V2 (RSA-3072 or ECDSA)",
"protecao_dpa": "No"
},
"wifi": "No",
"bluetooth": "No",
"ethernet": "Yes (Integrated Ethernet MAC)",
"memoria_sram": "768 KB",
"memoria_sram_rtc": "32 KB",
"memoria_rom": "128 KB (HP ROM) + 16 KB (LP ROM)",
"flash_externa": "Up to 128 MB via QSPI/Octal SPI",
"psram_externa": "16 MB or 32 MB integrated in package (OPI/HPI, 1.8 V)",
"gpio": "55",
"adc": "2x 12-bit SAR ADC, up to 14 channels",
"dac": "No",
"touch": "Yes (capacitive touch sensor)",
"uart": "6 (5 UART + 1 LP UART)",
"spi": "3",
"i2c": "3 (2 I2C + 1 LP I2C)",
"i2s": "4 (3 I2S + 1 LP I2S)",
"pwm": "LED PWM (up to 8 channels), Motor PWM (6 channels)",
"usb": "USB 2.0 High-Speed OTG + USB 2.0 Full-Speed OTG + USB Serial/JTAG",
"mipi_csi": "MIPI CSI camera interface",
"mipi_dsi": "MIPI DSI display interface",
"lcd": "8/16/24-bit LCD interface",
"camera": "8/16-bit DVP interface",
"sdio": "1 SD/MMC Host controller (SDHOST)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "15-150 mA (40 a 400 MHz, depending on load)",
"light_sleep": "75-800 µA",
"deep_sleep": "12 µA"
},
"temperatura_operacao": "-40°C to 85°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v5.3",
"arduino_core": "Yes (7 board definitions in official core)",
"encapsulamento": "QFN104 (10×10 mm)",
"modulos": "No module in official catalog (bare chip only)",
"datasheet": "https://documentation.espressif.com/esp32-p4-chip-revision-v1.3_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-p4-chip-revision-v1.3_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/get-started/index.html",
"placa": "/placas/esp32-p4.png",
"cor": "#ffc107"
},
"ESP32-H2": {
"nome_completo": "ESP32-H2",
"icone": "🔋",
"descricao": "Focused on ultra-low power with Bluetooth 6.0, Zigbee and Thread. No Wi-Fi support",
"arquitetura": "RISC-V single-core 32-bit",
"nucleos": "1 (Single-core)",
"frequencia": "Up to 96 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256",
"rsa": "Yes (RSA/MPI up to 3072 bits)",
"ecc": "Yes (P-192, P-256)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "Yes",
"assinatura_digital": "Yes",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128",
"secure_boot": "V2 (RSA-3072 or ECDSA)",
"protecao_dpa": "Yes"
},
"wifi": "No",
"bluetooth": "Bluetooth 5 (LE) (Bluetooth 5.3 certified)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Yes",
"memoria_sram": "320 KB",
"memoria_sram_rtc": "4 KB (LP Memory)",
"memoria_rom": "128 KB",
"flash_externa": "Up to 16 MB via QSPI",
"psram_externa": "No",
"gpio": "19",
"adc": "1x 12-bit SAR ADC, up to 5 channels",
"dac": "No",
"touch": "No",
"uart": "2",
"spi": "3",
"i2c": "2",
"i2s": "1",
"pwm": "LED PWM (up to 6 channels)",
"usb": "1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "24-140 mA (radio, from -24 to 20 dBm)",
"light_sleep": "25-85 µA",
"deep_sleep": "7 µA"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "-40°C to 150°C",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v5.1",
"arduino_core": "Yes (3 board definitions in official core)",
"encapsulamento": "QFN32 (4×4 mm)",
"modulos": "ESP32-H2-MINI-1, ESP32-H2-WROOM-02C",
"datasheet": "https://documentation.espressif.com/esp32-h2_datasheet_en.html",
"manual_tecnico": "https://documentation.espressif.com/esp32-h2_technical_reference_manual_en.html",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/get-started/index.html",
"placa": "/placas/esp32-h2.png",
"cor": "#6c757d"
},
"ESP32-H4": {
"nome_completo": "ESP32-H4",
"icone": "🛡️",
"descricao": "Ultra-high energy efficiency dual-core RISC-V SoC with Bluetooth 5.4 LE (LE Audio) and IEEE 802.15.4 for Thread, Zigbee and Matter. No Wi-Fi",
"status_documentacao": "Preliminary documentation: Espressif has not yet published the datasheet or technical reference manual for ESP32-H4. The data below comes from the official product announcement and ESP-IDF hardware definitions (soc_caps), and may change before release.",
"arquitetura": "RISC-V dual-core 32-bit",
"nucleos": "2 (Dual-core)",
"frequencia": "Up to 96 MHz",
"seguranca": {
"aes": "AES-128/256",
"sha": "SHA-1/224/256/384/512",
"rsa": "No",
"ecc": "Yes (P-192, P-256, P-384)",
"ecdsa": "Yes (deterministic mode, RFC 6979)",
"hmac": "Yes",
"assinatura_digital": "No",
"key_manager": "No",
"rng": "Yes (hardware TRNG)",
"criptografia_flash": "XTS-AES-128/256",
"secure_boot": "Yes in hardware; not yet enabled in ESP-IDF)",
"protecao_dpa": "No"
},
"wifi": "No",
"bluetooth": "Bluetooth 5.4 LE (Bluetooth 6.0 certified; LE Audio, isochronous channels BIS/CIS, PAwR, Connection Subrating and Direction Finding AoA/AoD)",
"zigbee_thread": "IEEE 802.15.4 (Zigbee 3.0, Thread 1.4)",
"matter": "Yes",
"memoria_sram": "384 KB",
"memoria_sram_rtc": "Yes (LP SRAM)",
"memoria_rom": "128 KB",
"flash_externa": "Yes, via QSPI (4 MB integrated in package on ESP32-H4HF4)",
"psram_externa": "Yes (2 MB integrated in package on ESP32-H4HR2)",
"gpio": "40",
"adc": "1x 12-bit SAR ADC, up to 5 channels",
"dac": "No",
"touch": "15 capacitive channels (version 3, with waterproof and proximity)",
"uart": "2",
"spi": "3",
"i2c": "2",
"i2s": "1",
"pwm": "LED PWM (up to 8 channels), Motor PWM (MCPWM)",
"can": "1 (CAN 2.0, TWAI®)",
"usb": "1 (USB OTG 1.1) + 1 (USB Serial/JTAG)",
"sensor_temperatura": "1 (internal)",
"consumo_energia": {
"active": "Not disclosed (preliminary documentation)"
},
"temperatura_operacao": "-40°C to 105°C",
"temperatura_armazenamento": "Not disclosed (preliminary documentation)",
"depuracao": "Integrated JTAG via USB (no external probe required)",
"esp_idf_minimo": "v6.0 preview (no stable support)",
"arduino_core": "Not yet supported by arduino-esp32 core",
"encapsulamento": "QFN56 (6×6 mm)",
"modulos": "ESP32-H4-WROOM-1",
"guia_de_programacao": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32h4/get-started/index.html",
"cor": "#e83e8c"
}
}
+422
View File
@@ -0,0 +1,422 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"Conexión de antena de RF (Wi-Fi y Bluetooth)"
],
"categorias": [
"Antena",
"RF"
],
"avisos": [
"Pin de RF dedicado. Evite trazar pistas largas o sin acoplamiento de impedancia de 50 ohms."
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Alimentación analógica de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V (3.0V a 3.6V)",
"Suministra energía a los circuitos analógicos y de RF del chip"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Alimentación analógica de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V (3.0V a 3.6V)",
"Suministra energía a los circuitos analógicos y de RF del chip"
]
},
{
"numero": "4",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Pin de entrada analógica ADC1 Canal 0"
]
},
{
"numero": "5",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO1",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Pin de entrada analógica ADC1 Canal 1"
]
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI"
],
"avisos": [
"Mapeado a la función SPI MISO (FSPIQ) por defecto durante el arranque de la flash"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Habilitar el chip (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Activo en alto. Lleve a nivel alto para iniciar el chip.",
"No deje este pin flotando. Use un circuito RC de retardo externo para un arranque estable."
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Pin de entrada analógica ADC1 Canal 3"
]
},
{
"numero": "9",
"nome": "GPIO4",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO4",
"MTMS",
"FSPIQ",
"ADC1_CH4"
],
"categorias": [
"GPIO",
"JTAG",
"SPI",
"ADC"
],
"avisos": [
"Pin multifuncional: JTAG MTMS, SPI2 MISO y ADC1 Canal 4.",
"Puede usarse para depuración JTAG junto con otros pines JTAG."
]
},
{
"numero": "10",
"nome": "GPIO5",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO5",
"MTDI",
"FSPIWP"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Pin multifuncional: JTAG MTDI y SPI2 Write Protect (FSPIWP)."
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"Alimentación del dominio RTC e I/Os de bajo consumo"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V"
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO6",
"MTCK",
"FSPICLK"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Pin multifuncional: JTAG MTCK y SPI2 Clock (FSPICLK)."
]
},
{
"numero": "13",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO7",
"MTDO",
"FSPID"
],
"categorias": [
"GPIO",
"JTAG",
"SPI"
],
"avisos": [
"Pin multifuncional: JTAG MTDO y SPI2 MOSI (FSPID)."
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Pin de strapping para control de arranque.",
"Junto con GPIO9, selecciona el modo de arranque del SoC (debe estar en 1 durante el reinicio para Joint Download Boot si GPIO9=0)."
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Pin de strapping principal. Nivel alto (1) en el reinicio activa SPI Boot (predeterminado vía pull-up débil).",
"Nivel bajo (0) en el reinicio coloca el chip en modo de descarga UART/SPI."
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin multifuncional: SPI2 Chip Select 0 (FSPICS0)."
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Alimentación digital de la CPU e I/Os correspondientes (3.3V)"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V"
]
},
{
"numero": "18",
"nome": "GPIO18",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO18"
],
"categorias": [
"GPIO"
]
},
{
"numero": "19",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO19",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Pin de recepción UART0 (Serial RX por defecto para grabación y monitorización)."
]
},
{
"numero": "20",
"nome": "GPIO20",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO20",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Pin de transmisión UART0 (Serial TX por defecto para grabación y monitorización)."
]
},
{
"numero": "21",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Alimentación de entrada analógica de 3.3V"
],
"categorias": [
"Power"
]
},
{
"numero": "22",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Conexión externa del cristal oscilador (Salida)"
],
"categorias": [
"Clock"
]
},
{
"numero": "23",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Conexión externa del cristal oscilador (Entrada)"
],
"categorias": [
"Clock"
]
},
{
"numero": "24",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Alimentación de entrada analógica de 3.3V"
],
"categorias": [
"Power"
]
},
{
"numero": "25",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Pin de conexión a tierra central (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Debe soldarse adecuadamente al plano de tierra (GND) de la PCB para un rendimiento estable y disipación térmica."
]
}
]
+643
View File
@@ -0,0 +1,643 @@
[
{
"numero": "1",
"nome": "LNA_IN",
"tipo": "analog",
"funcoes": [
"Entrada y salida de señales de RF (Wi-Fi y Bluetooth) para la antena"
],
"categorias": [
"Antena"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "3",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "4",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO0",
"XTAL_32K_P",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
]
},
{
"numero": "5",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
]
},
{
"numero": "6",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO2",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"En realidad, este pin no determina el modo de arranque, pero se recomienda conectarlo con un pull-up para evitar transitorios (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "7",
"nome": "CHIP_EN",
"tipo": "analog",
"funcoes": [
"Habilitar el chip"
],
"categorias": [
"Power"
],
"avisos": [
"Llevar este pin a nivel alto habilitará el funcionamiento del chip",
"Llevar este pin a nivel bajo deshabilitará el funcionamiento del chip",
"No deje este pin flotando, utilice una resistencia pull-up externa"
]
},
{
"numero": "8",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO3",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"ADC"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "9",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO4",
"ADC1_CH4",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "10",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDD3P3_RTC"
],
"funcoes": [
"GPIO5",
"ADC2_CH0",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "11",
"nome": "VDD3P3_RTC",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio de bajo consumo y parte del dominio digital"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO7",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO10",
"FSPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "17",
"nome": "VDD3P3_CPU",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "18",
"nome": "VDD_SPI",
"tipo": "power",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"Entrada/salida de la alimentación de la flash interna/externa",
"GPIO11"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip",
"Solo puede utilizarse como GPIO si la memoria flash está alimentada por una fuente externa"
]
},
{
"numero": "19",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO12",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "20",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO13",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "21",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO14",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "22",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO15",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "23",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO16",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "24",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDD3P3_CPU"
],
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "25",
"nome": "GPIO18",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO18",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "26",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO19",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "27",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO20",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "28",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDD3P3_CPU"
],
"funcoes": [
"GPIO21",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Tras el reinicio, este pin estará con el pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "29",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Entrada/Salida negativa de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.2 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "30",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Entrada/Salida positiva de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.2 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "31",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "32",
"nome": "VDDA",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
}
]
+944
View File
@@ -0,0 +1,944 @@
[
{
"numero": "1",
"nome": "VDDA6",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "2",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
},
{
"numero": "3",
"nome": "VDDA7",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "4",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Entrada/Salida negativa de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.3 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "5",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Entrada/Salida positiva de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.3 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "6",
"nome": "VDDA8",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "7",
"nome": "CHIP_PU",
"tipo": "analog",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"Habilitar el chip"
],
"categorias": [
"Power"
],
"avisos": [
"Llevar este pin a nivel alto habilitará el funcionamiento del chip",
"Llevar este pin a nivel bajo deshabilitará el funcionamiento del chip",
"No deje este pin flotando, utilice una resistencia pull-up externa"
]
},
{
"numero": "8",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital de bajo consumo"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "9",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
]
},
{
"numero": "10",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
]
},
{
"numero": "11",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"LP_I2C_SDA",
"ADC1_CH1",
"FSPIQ",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"SPI",
"JTAG",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"La función I2C_SDA está disponible en el modo de bajo consumo (LP)",
"Pin utilizado para depuración",
"Utilizado para controlar la frecuencia del cristal oscilador del chip (consulte la sección 3.5 de la hoja de datos para más detalles)"
]
},
{
"numero": "12",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"LP_I2C_SCL",
"ADC1_CH2",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"I2C",
"ADC",
"JTAG",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"La función I2C_SDA está disponible en el modo de bajo consumo (LP)",
"Pin utilizado para depuración",
"Utilizado para controlar la temporización de SDIO Slave (consulte la sección 3.2 de la hoja de datos para más detalles)"
]
},
{
"numero": "13",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "14",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH4",
"FSPIWP",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "15",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"LP_GDIO6",
"ADC1_CH5",
"FSPICLK"
],
"categorias": [
"GPIO",
"Low Power",
"ADC",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "16",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO7",
"FSPID",
"SDIO_DATA1"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar la fuente de señales JTAG (consulte la sección 3.4 de la hoja de datos para más detalles)"
]
},
{
"numero": "17",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO8",
"SDIO_DATA0",
"PAD_COMP0"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "18",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO9",
"SDIO_CLK",
"PAD_COMP1"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "19",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO10",
"FSPICS0",
"SDIO_CMD"
],
"categorias": [
"GPIO",
"SPI",
"SD"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "20",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Tras el reinicio, este pin estará con el pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "21",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO12",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "22",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D-",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "23",
"nome": "GPIO14",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO14",
"USB_D+",
"SDIO_DATA4"
],
"categorias": [
"GPIO",
"USB",
"SD"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno para USB activado",
"Tras el reinicio, este pin estará configurado como entrada con el pull-up interno para USB activado",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "24",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital de alto rendimiento y parte del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "25",
"nome": "SPICS1",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO15",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "26",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO16",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "27",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO17",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "28",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO18",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "29",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Salida de alimentación para la flash externa",
"GPIO19"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip",
"Solo puede utilizarse como GPIO si la memoria flash externa está alimentada por una fuente externa"
]
},
{
"numero": "30",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO20",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "31",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO21",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "32",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO22",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "33",
"nome": "GPIO23",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO23"
],
"categorias": [
"GPIO"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "34",
"nome": "GPIO24",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "35",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO25"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar la temporización de SDIO Slave (consulte la sección 3.4 de la hoja de datos para mais detalles)"
]
},
{
"numero": "36",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO26"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "37",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO27"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)",
"Utilizado para controlar la emisión de mensajes de la ROM en UART0 (consulte la sección 3.3 de la hoja de datos para más detalles)"
]
},
{
"numero": "38",
"nome": "GPIO28",
"tipo": "io",
"alimentacao": [
"VDDPST3"
],
"funcoes": [
"GPIO28"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "39",
"nome": "VDDPST3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital de alto rendimiento"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "40",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "41",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "42",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"Conexión de la antena RF para la banda de 2 GHz"
],
"categorias": [
"Antena"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "43",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
},
{
"numero": "44",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "44",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "45",
"nome": "VDDA5",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "47",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
},
{
"numero": "48",
"nome": "ANT_5G",
"tipo": "analog",
"funcoes": [
"Conexión de la antena RF para la banda de 5 GHz"
],
"categorias": [
"Antena"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
}
]
+841
View File
@@ -0,0 +1,841 @@
[
{
"numero": "1",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"Conexión de la antena RF"
],
"categorias": [
"Antena"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "2",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "3",
"nome": "VDDA3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Habilitar el chip"
],
"categorias": [
"Power"
],
"avisos": [
"Llevar este pin a nivel alto habilitará el funcionamiento del chip",
"Llevar este pin a nivel bajo deshabilitará el funcionamiento del chip",
"No deje este pin flotando, utilice una resistencia pull-up externa"
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital de bajo consumo y parte del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "6",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"LP_GDIO0",
"XTAL_32K_P",
"LP_UART_DTRN",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART"
]
},
{
"numero": "7",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"LP_GDIO1",
"XTAL_32K_N",
"LP_UART_DSRN",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"Low Power",
"Clock",
"UART",
"ADC"
]
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2",
"LP_GDIO2",
"LP_UART_RTSN",
"ADC1_CH2",
"FSPIQ"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"LP_GDIO3",
"LP_UART_CTSN",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "10",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"LP_GDIO4",
"LP_UART_RXD",
"ADC1_CH3",
"FSPIHD",
"MTMS"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración",
"Utilizado para controlar la temporización de SDIO Slave (consulte la sección 3.2 de la hoja de datos para más detalles)"
]
},
{
"numero": "11",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"LP_GDIO5",
"LP_UART_TXD",
"ADC1_CH5",
"FSPIWP",
"MTDI"
],
"categorias": [
"GPIO",
"Low Power",
"UART",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración",
"Utilizado para controlar la temporización de SDIO Slave (consulte la sección 3.2 de la hoja de datos para más detalles)"
]
},
{
"numero": "12",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"LP_GDIO6",
"LP_I2C_SDA",
"ADC1_CH6",
"FSPICLK",
"MTCK"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"ADC",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"La función I2C_SDA está disponible en el modo de bajo consumo (LP)",
"Pin utilizado para depuración"
]
},
{
"numero": "13",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO7",
"LP_GDIO7",
"LP_I2C_SCL",
"FSPID",
"MTDO"
],
"categorias": [
"GPIO",
"Low Power",
"I2C",
"SPI",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"La función I2C_SDA está disponible en el modo de bajo consumo (LP)",
"Pin utilizado para depuración"
]
},
{
"numero": "14",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)",
"Utilizado para controlar la emisión de mensajes de la ROM en UART0 (consulte la sección 3.3 de la hoja de datos para más detalles)"
]
},
{
"numero": "15",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "16",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO10"
],
"categorias": [
"GPIO"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "17",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO11"
],
"categorias": [
"GPIO"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "18",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "19",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "20",
"nome": "SPICS0",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO24",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "21",
"nome": "SPIQ",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO25",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "22",
"nome": "SPIWP",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO26",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "23",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Entrada/Salida de alimentación para la memoria flash",
"GPIO27"
],
"categorias": [
"Power",
"GPIO"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip",
"Solo puede utilizarse como GPIO si la memoria flash externa está alimentada por una fuente externa"
]
},
{
"numero": "24",
"nome": "SPIHD",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO28",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "25",
"nome": "SPICLK",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO29",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "26",
"nome": "SPID",
"tipo": "io",
"alimentacao": [
"VDD_SPI"
],
"funcoes": [
"GPIO30",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado por la memoria flash SPI",
"No se recomienda utilizar este pin como GPIO"
]
},
{
"numero": "27",
"nome": "GPIO15",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO15"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar la fuente de señales JTAG (consulte la sección 3.4 de la hoja de datos para más detalles)"
]
},
{
"numero": "28",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio digital de alto rendimiento"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "29",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO16",
"U0TXD",
"FSPICS0"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Tras el reinicio, este pin estará con el pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "30",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO17",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "31",
"nome": "SDIO_CMD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO18",
"SDIO_CMD",
"FSPICS2"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "32",
"nome": "SDIO_CLK",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO19",
"SDIO_CLK",
"FSPICS3"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "33",
"nome": "SDIO_DATA0",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO20",
"SDIO_DATA0",
"FSPICS4"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "34",
"nome": "SDIO_DATA1",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO21",
"SDIO_DATA1",
"FSPICS5"
],
"categorias": [
"GPIO",
"SD",
"SPI"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "35",
"nome": "SDIO_DATA2",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22",
"SDIO_DATA2"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "36",
"nome": "SDIO_DATA3",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"SDIO_DATA3"
],
"categorias": [
"GPIO",
"SD"
],
"avisos": [
"Durante el reinicio, este pin estará con el pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada"
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Entrada/Salida negativa de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Entrada/Salida positiva de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "41",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
}
]
+729
View File
@@ -0,0 +1,729 @@
[
{
"numero": "1",
"nome": "ANT_2G",
"tipo": "analog",
"funcoes": [
"Conexión de antena de RF (Wi-Fi y Bluetooth)"
],
"categorias": [
"Antena",
"RF"
],
"avisos": [
"Pin de RF dedicado a 2.4 GHz. Requer casamento de impedância de 50 ohms."
]
},
{
"numero": "2",
"nome": "VDDA3",
"tipo": "power",
"funcoes": [
"Alimentación del dominio analógico de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V (3.0V a 3.6V). Fornece energia para circuitos de RF e clock."
]
},
{
"numero": "3",
"nome": "VDDA4",
"tipo": "power",
"funcoes": [
"Alimentación del dominio analógico de 3.3V"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V (3.0V a 3.6V). Fornece energia para circuitos de RF e clock."
]
},
{
"numero": "4",
"nome": "CHIP_PU",
"tipo": "analog",
"funcoes": [
"Habilitar el chip (Power-up / Reset)"
],
"categorias": [
"Power"
],
"avisos": [
"Activo en alto. Lleve a nivel alto para iniciar el chip.",
"No deje este pin flotando. Se recomienda usar un circuito RC de retardo externo para un reinicio limpio."
]
},
{
"numero": "5",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Alimentación digital de los dominios HP (High Performance) y LP (Low Power)"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V. Alimenta a parte digital de baixo consumo e pinos associados."
]
},
{
"numero": "6",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
],
"avisos": [
"Pin multifuncional de bajo consumo. Puede conectarse al cristal oscilador de 32 kHz externo (Entrada P)."
]
},
{
"numero": "7",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"XTAL_32K_N",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"Clock",
"ADC"
],
"avisos": [
"Pin multifuncional. Conexión del cristal de 32 kHz externo (Salida N) y entrada analógica ADC1 Canal 0."
]
},
{
"numero": "8",
"nome": "GPIO2",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO2"
],
"categorias": [
"GPIO"
]
},
{
"numero": "9",
"nome": "GPIO3",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"MTMS",
"ADC1_CH1"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Pin multifuncional: JTAG MTMS, ADC1 Canal 1 y pin de strapping para control de flanco de reloj de SDIO.",
"Flotante por defecto durante el reinicio."
]
},
{
"numero": "10",
"nome": "GPIO4",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"MTDI",
"ADC1_CH2"
],
"categorias": [
"GPIO",
"JTAG",
"ADC",
"Strapping"
],
"avisos": [
"Pin multifuncional: JTAG MTDI, ADC1 Canal 2 y pin de strapping para control de flanco de reloj de SDIO.",
"Flotante por defecto durante el reinicio."
]
},
{
"numero": "11",
"nome": "GPIO5",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"MTCK",
"ADC1_CH3"
],
"categorias": [
"GPIO",
"JTAG",
"ADC"
],
"avisos": [
"Pin multifuncional: JTAG MTCK e entrada analógica ADC1 Canal 3."
]
},
{
"numero": "12",
"nome": "GPIO6",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO6",
"MTDO"
],
"categorias": [
"GPIO",
"JTAG"
],
"avisos": [
"Pin multifuncional JTAG MTDO."
]
},
{
"numero": "13",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO25",
"SDIO_CMD",
"FSPICS0"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin multifuncional de alta velocidade: SDIO Comando ou SPI2 Chip Select 0."
]
},
{
"numero": "14",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO26",
"SDIO_CLK",
"FSPICLK"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin multifuncional de alta velocidade: SDIO Clock ou SPI2 Clock."
]
},
{
"numero": "15",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO27",
"SDIO_DATA0",
"FSPID"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin multifuncional de alta velocidade: SDIO Dados 0 ou SPI2 MOSI (FSPID)."
]
},
{
"numero": "16",
"nome": "GPIO28",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO28",
"SDIO_DATA1",
"FSPIQ"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin de alta velocidade: SDIO Dados 1 ou SPI2 MISO (FSPIQ)."
]
},
{
"numero": "17",
"nome": "GPIO22",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22",
"SDIO_DATA2",
"FSPIWP"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin de alta velocidade: SDIO Dados 2 ou SPI2 Write Protect."
]
},
{
"numero": "18",
"nome": "GPIO23",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"SDIO_DATA3",
"FSPIHD"
],
"categorias": [
"GPIO",
"SDIO",
"SPI"
],
"avisos": [
"Pin de alta velocidade: SDIO Dados 3 ou SPI2 Hold."
]
},
{
"numero": "19",
"nome": "GPIO14",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO14",
"SPICS1"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin dedicado para Chip Select 1 de la interfaz de memoria SPI Flash/PSRAM."
]
},
{
"numero": "20",
"nome": "GPIO15",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO15",
"SPICS0"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin dedicado para Chip Select 0 de la interfaz de memoria SPI Flash."
]
},
{
"numero": "21",
"nome": "VDDPST2",
"tipo": "power",
"funcoes": [
"Alimentación del dominio digital HP (High Performance)"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V (3.0V a 3.6V). Alimenta as interfaces digitais rápidas."
]
},
{
"numero": "22",
"nome": "GPIO16",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO16",
"SPIQ"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin de datos Q (MISO) de la interfaz de memoria flash SPI."
]
},
{
"numero": "23",
"nome": "GPIO17",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO17",
"SPIWP"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin de protección contra escritura (Write Protect) de la interfaz de memoria flash SPI."
]
},
{
"numero": "24",
"nome": "VDD_SPI",
"tipo": "power",
"funcoes": [
"Tensión de salida LDO gerada a partir de VDDPST2 para lalimentar a flash e PSRAM"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión de salida configurable por software de acuerdo con las especificaciones de la flash interna/externa (normalmente 3.3V o 1.8V).",
"No debe usarse como fuente general de energía de alta corriente."
]
},
{
"numero": "25",
"nome": "GPIO19",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO19",
"SPIHD"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin de control de Hold de la interfaz de memoria flash SPI."
]
},
{
"numero": "26",
"nome": "GPIO20",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO20",
"SPICLK"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin de señal de reloj de la interfaz de memoria flash SPI."
]
},
{
"numero": "27",
"nome": "GPIO21",
"tipo": "io",
"alimentacao": [
"VDD_SPI",
"VDDPST2"
],
"funcoes": [
"GPIO21",
"SPID"
],
"categorias": [
"GPIO",
"SPI"
],
"avisos": [
"Pin de datos D (MOSI) de la interfaz de memoria flash SPI."
]
},
{
"numero": "28",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO12",
"USB_D-"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Pin de señal negativa del transceptor USB Serial/JTAG integrado."
]
},
{
"numero": "29",
"nome": "GPIO13",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO13",
"USB_D+"
],
"categorias": [
"GPIO",
"USB"
],
"avisos": [
"Pin de señal positiva del transceptor USB Serial/JTAG integrado.",
"Dispone de pull-up integrado activado por defecto en el arranque del USB."
]
},
{
"numero": "30",
"nome": "GPIO24",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24"
],
"categorias": [
"GPIO"
]
},
{
"numero": "31",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Pin de strapping para selección del modo de arranque y control de emisión de mensajes de la ROM.",
"Flotante por defecto durante el reinicio. Nivel alto (1) activa la emisión del registro de arranque."
]
},
{
"numero": "32",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Pin de strapping principal para selección del modo de arranque.",
"Equipado con pull-up débil integrado. Nivel alto (1) en el reinicio activa SPI Boot (carga desde la flash). Nivel bajo (0) fuerza el modo Download."
]
},
{
"numero": "33",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO10",
"U0RXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Recepción serial UART0 (Serial RX para grabación del firmware externa y depuración)."
]
},
{
"numero": "34",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO11",
"U0TXD"
],
"categorias": [
"GPIO",
"UART"
],
"avisos": [
"Transmisión serial UART0 (Serial TX para grabación del firmware externa y depuración)."
]
},
{
"numero": "35",
"nome": "GPIO29",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO29"
],
"categorias": [
"GPIO"
]
},
{
"numero": "36",
"nome": "GPIO7",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO7"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Pin de strapping para selección de la fuente de señales JTAG (arranque temprano).",
"Sin resistencias de pull internas en el reinicio. Debe mantenerse estable mediante circuito externo si se utiliza."
]
},
{
"numero": "37",
"nome": "VDDA1",
"tipo": "power",
"funcoes": [
"Alimentación del dominio analógico de 3.3V"
],
"categorias": [
"Power"
]
},
{
"numero": "38",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Conexión externa del cristal oscilador de 40 MHz (Salida N)"
],
"categorias": [
"Clock"
]
},
{
"numero": "39",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Conexión externa del cristal oscilador de 40 MHz (Entrada P)"
],
"categorias": [
"Clock"
]
},
{
"numero": "40",
"nome": "VDDA2",
"tipo": "power",
"funcoes": [
"Alimentación del dominio analógico de 3.3V"
],
"categorias": [
"Power"
]
},
{
"numero": "41",
"nome": "GND",
"tipo": "power",
"funcoes": [
"Pin de conexión a tierra central (Exposed Pad)"
],
"categorias": [
"Power"
],
"avisos": [
"Debe soldarse adecuadamente al plano de masa (GND) de la PCB para un control de RF y térmico estable."
]
}
]
+603
View File
@@ -0,0 +1,603 @@
[
{
"numero": "1",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "2",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "3",
"nome": "GPIO0",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO0",
"FSPIQ"
],
"categorias": [
"GPIO",
"SPI"
]
},
{
"numero": "4",
"nome": "GPIO1",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"FSPICS0",
"ADC1_CH0"
],
"categorias": [
"GPIO",
"SPI",
"ADC"
]
},
{
"numero": "5",
"nome": "MTMS",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO1",
"FSPIWP",
"ADC1_CH1",
"MTMS"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "6",
"nome": "MTDO",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO3",
"FSPIHD",
"ADC1_CH2",
"MTDO"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "7",
"nome": "MTCK",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO4",
"FSPICLK",
"ADC1_CH3",
"MTCK"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "8",
"nome": "MTDI",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO5",
"FSPID",
"ADC1_CH4",
"MTDI"
],
"categorias": [
"GPIO",
"SPI",
"ADC",
"JTAG"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Pin utilizado para depuración"
]
},
{
"numero": "9",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio de E/S"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "10",
"nome": "GPIO8",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO8"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)",
"Utilizado para controlar la emisión de mensajes de la ROM en UART0 (consulte la sección 3.3 de la hoja de datos para más detalles)"
]
},
{
"numero": "11",
"nome": "GPIO9",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO9"
],
"categorias": [
"GPIO",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Utilizado para controlar el modo de arranque del chip (consulte la sección 3.1 de la hoja de datos para más detalles)"
]
},
{
"numero": "12",
"nome": "GPIO10",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO10",
"ZCD0"
],
"categorias": [
"GPIO"
]
},
{
"numero": "13",
"nome": "GPIO11",
"tipo": "io",
"alimentacao": [
"VDDPST1"
],
"funcoes": [
"GPIO11",
"ZCD1"
],
"categorias": [
"GPIO"
]
},
{
"numero": "14",
"nome": "GPIO12",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO12"
],
"categorias": [
"GPIO"
]
},
{
"numero": "15",
"nome": "XTAL_32K_P",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO13",
"XTAL_32K_P"
],
"categorias": [
"GPIO",
"Clock"
]
},
{
"numero": "16",
"nome": "XTAL_32K_N",
"tipo": "io",
"alimentacao": [
"VDDA_PMU",
"VBAT"
],
"funcoes": [
"GPIO14",
"XTAL_32K_N"
],
"categorias": [
"GPIO",
"Clock"
]
},
{
"numero": "17",
"nome": "CHIP_EN",
"tipo": "analog",
"alimentacao": [
"VBAT"
],
"funcoes": [
"Habilitar el chip"
],
"categorias": [
"Power"
],
"avisos": [
"Llevar este pin a nivel alto habilitará el funcionamiento del chip",
"Llevar este pin a nivel bajo deshabilitará el funcionamiento del chip",
"No deje este pin flotando, utilice una resistencia pull-up externa"
]
},
{
"numero": "18",
"nome": "VBAT",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico o de la batería"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "19",
"nome": "VDDA_PMU",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "20",
"nome": "VDDPST1",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio de E/S"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "21",
"nome": "GPIO22",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO22"
],
"categorias": [
"GPIO"
]
},
{
"numero": "22",
"nome": "U0RXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO23",
"U0RXD",
"FSPICS1"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "23",
"nome": "U0TXD",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24",
"U0TXD",
"FSPICS2"
],
"categorias": [
"GPIO",
"UART",
"SPI"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con pull-up interno activado",
"Pin utilizado para depuración"
]
},
{
"numero": "24",
"nome": "GPIO25",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO24",
"FSPICS3"
],
"categorias": [
"GPIO",
"SPI",
"Strapping"
],
"avisos": [
"Durante el reinicio, este pin estará configurado como entrada",
"Tras el reinicio, este pin estará configurado como entrada",
"Utilizado para controlar la fuente de señales JTAG (consulte la sección 3.3 de la hoja de datos para más detalles)"
]
},
{
"numero": "25",
"nome": "GPIO26",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO26",
"FSPICS4",
"USB_D-"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "26",
"nome": "GPIO27",
"tipo": "io",
"alimentacao": [
"VDDPST2"
],
"funcoes": [
"GPIO27",
"FSPICS5",
"USB_D+"
],
"categorias": [
"GPIO",
"SPI",
"USB"
],
"avisos": [
"Tras el reinicio, este pin estará configurado como entrada con el pull-up interno para USB activado",
"Por defecto, este pin se utiliza para USB Serial/JTAG"
]
},
{
"numero": "27",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "28",
"nome": "XTAL_N",
"tipo": "analog",
"funcoes": [
"Entrada/Salida negativa de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.2 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "29",
"nome": "XTAL_P",
"tipo": "analog",
"funcoes": [
"Entrada/Salida positiva de reloj"
],
"categorias": [
"Clock"
],
"avisos": [
"Consulte la sección 2.3.2 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "30",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "31",
"nome": "VDD3P3",
"tipo": "power",
"funcoes": [
"Entrada de alimentación del dominio analógico"
],
"categorias": [
"Power"
],
"avisos": [
"Tensión recomendada: 3.3V",
"Tensión mínima recomendada: 3.0V",
"Tensión máxima recomendada: 3.6V",
"Consulte la sección 2.5 de la hoja de datos para más detalles sobre la alimentación del chip"
]
},
{
"numero": "32",
"nome": "ANT",
"tipo": "analog",
"funcoes": [
"Conexión de la antena RF"
],
"categorias": [
"Antena"
],
"avisos": [
"Consulte la sección 2.4 de la hoja de datos para más detalles sobre pines analógicos"
]
},
{
"numero": "33",
"nome": "GND",
"tipo": "ground",
"funcoes": [
"Referencia eléctrica del circuito (tierra)"
],
"categorias": [
"GND"
]
}
]
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
Loaded 100 of 262 files, more files were not shown because too many files have changed in this diff. Show more