mirror of
https://github.com/deunix-educ/voice-assistant.git
synced 2026-10-13 00:11:57 +02:00
Assistant vocal local ESP32 : étapes 1 à 15, et 15b écrite
État du projet au premier commit : - firmware ESP32 : micro I2S, lecture anti-gigue, MQTT (état retenu, testament), mains libres, domotique de démonstration, chien de garde, présence du serveur ; - serveur Python : sessions, VAD, faster-whisper, pyannote, identification, droits par profil, domotique, mot de réveil, Piper ; - broker Mosquitto : configuration, comptes et ACL (non activés en développement) ; - étape 15b écrite, en attente d'essai : agent MQTT pour machines Linux. Étapes 1 à 15 validées. 203 tests, pyright sans erreur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
# Brochage et câblage — ESP32-WROOM-32 + INMP441 + MAX98357A
|
||||
|
||||
Document de référence du câblage. Schéma visuel : [wiring.svg](wiring.svg)
|
||||
(clic droit → « Open Preview » dans VSCodium, ou ouverture dans un navigateur).
|
||||
|
||||
> **Avant de câbler** : ESP32 débranché de l'USB. On ne modifie jamais un câblage
|
||||
> sous tension : une inversion VDD/GND détruit l'INMP441 en quelques secondes.
|
||||
|
||||
---
|
||||
|
||||
## 1. Tableau de câblage complet
|
||||
|
||||
Carte de référence : **DOIT ESP32 DEVKIT V1, 30 broches** (la plus répandue en TP).
|
||||
Sur une carte 38 broches, les numéros de GPIO sont identiques, seule leur position
|
||||
physique change : **fiez-vous toujours aux numéros sérigraphiés**, jamais au rang.
|
||||
|
||||
### 1.1 Micro INMP441 (I2S0, réception)
|
||||
|
||||
| INMP441 | ESP32 | Fil conseillé | Rôle |
|
||||
|---|---|---|---|
|
||||
| `VDD` | **3V3** | rouge | alimentation **3,3 V uniquement** |
|
||||
| `GND` | **GND** | noir | masse |
|
||||
| `SCK` | **GPIO 25** | bleu | horloge bit (BCLK), générée par l'ESP32 |
|
||||
| `WS` | **GPIO 26** | vert | sélection de mot (word select / LRCL) |
|
||||
| `SD` | **GPIO 33** | violet | donnée série, micro → ESP32 |
|
||||
| `L/R` | **GND** | noir | choix du canal : GND = **gauche** |
|
||||
|
||||
`L/R` à GND est la référence de ce projet : gardez ce câblage.
|
||||
|
||||
Attention à un piège propre à l'ESP32 : l'INMP441 n'émet que pendant **une moitié
|
||||
de trame** et sort des **zéros** pendant l'autre. Or la correspondance entre la
|
||||
broche `L/R` et les constantes `I2S_STD_SLOT_LEFT` / `..._RIGHT` du pilote n'est
|
||||
pas celle qu'on attend sur l'ESP32 d'origine. Écouter la mauvaise moitié donne un
|
||||
flux **parfaitement nul**, alors que le câblage est correct — le symptôme le plus
|
||||
déroutant de l'étape 1.
|
||||
|
||||
Le firmware tranche donc tout seul : au démarrage, la classe `MicSelfTest`
|
||||
réveille le micro **une seule fois**, lit les deux moitiés de trame en cadrage
|
||||
MSB et décide sur la **structure** des mots : la moitié utile est celle qui n'est
|
||||
ni nulle ni constante, et elle doit porter exactement **24 bits utiles**. Si elle
|
||||
en porte 25, le micro suit le cadrage Philips et le firmware bascule. Le niveau
|
||||
au repos est affiché pour information, sans intervenir dans la décision.
|
||||
|
||||
### 1.2 Amplificateur MAX98357A (I2S1, émission) — étape 2
|
||||
|
||||
| MAX98357A | ESP32 | Fil | Rôle |
|
||||
|---|---|---|---|
|
||||
| `Vin` | **VIN (5 V)** | orange | alimentation 5 V (3,3 V possible mais 4× moins de puissance) |
|
||||
| `GND` | **GND** | noir | masse |
|
||||
| `BCLK` | **GPIO 27** | bleu | horloge bit |
|
||||
| `LRC` | **GPIO 14** | vert | sélection de mot |
|
||||
| `DIN` | **GPIO 22** | violet | donnée série, ESP32 → ampli |
|
||||
| `GAIN` | *non connecté* | — | gain 9 dB par défaut (voir §4) |
|
||||
| `SD` | *non connecté* | — | déjà tiré au + par 100 kΩ sur la carte → ampli actif |
|
||||
| `+` / `−` | haut-parleur | — | sortie pontée : **jamais de masse sur `−`** |
|
||||
|
||||
### 1.3 Interface utilisateur
|
||||
|
||||
| Élément | ESP32 | Câblage |
|
||||
|---|---|---|
|
||||
| Bouton PTT | **GPIO 4** | une borne sur GPIO 4, l'autre sur **GND** — pull-up interne activé par le firmware |
|
||||
| LED d'état | **GPIO 2** | GPIO 2 → résistance **330 Ω** → anode LED ; cathode → GND |
|
||||
|
||||
La carte DevKit V1 possède déjà une LED bleue sur GPIO 2 : la LED externe est
|
||||
**optionnelle**, l'étape 1 est validable sans elle.
|
||||
|
||||
### 1.4 Haut-parleur
|
||||
|
||||
| Caractéristique | Valeur conseillée |
|
||||
|---|---|
|
||||
| Impédance | **4 Ω** (3 W) ou 8 Ω (2 W) |
|
||||
| Diamètre | 40 à 66 mm |
|
||||
| Câblage | directement sur `+` et `−` de l'ampli |
|
||||
|
||||
La sortie du MAX98357A est **pontée** (les deux fils sont actifs, en opposition
|
||||
de phase). Relier `−` à la masse court-circuite l'étage de sortie.
|
||||
|
||||
---
|
||||
|
||||
## 2. Schéma ASCII
|
||||
|
||||
```
|
||||
ESP32-WROOM-32 (DevKit V1, 30 broches)
|
||||
+----------------------------------------+
|
||||
INMP441 | |
|
||||
+---------+ | EN GPIO23 |
|
||||
| VDD o--|--rouge------|--------------------------------> 3V3 | (broche 3V3)
|
||||
| GND o--|--noir-------|---------------------------------> GND | (broche GND)
|
||||
| SD o--|--violet---->| GPIO33 GPIO22 |<--violet--+
|
||||
| SCK o--|--bleu------>| GPIO25 GPIO4 |<--+ |
|
||||
| WS o--|--vert------>| GPIO26 GPIO2 |---|--+ |
|
||||
| L/R o--|--noir--> GND| GPIO27 -->--bleu----------+ .. | | | |
|
||||
+---------+ | GPIO14 -->--vert--------+ | .. | | | |
|
||||
3,3 V SEULEMENT | | | VIN(5V)| | | |
|
||||
+-------------------------|-|------------+ | | |
|
||||
| | | | |
|
||||
+-------------+ | | | |
|
||||
| +-----------+ | | |
|
||||
v v | | |
|
||||
MAX98357A | | | | |
|
||||
+----------|---|-----+ | | |
|
||||
| LRC o<--+ | | | | |
|
||||
| BCLK o<------+ | HP 4 ohms / 3 W | | |
|
||||
| DIN o<------------|----------------------|--|----+
|
||||
| GAIN o (non conn. = 9 dB) | |
|
||||
| SD o (non conn. = actif) + o---+ | |
|
||||
| GND o---noir--> GND - o---|--+ | |
|
||||
| Vin o---orange--> VIN (5 V) | | | |
|
||||
+------------------------------+ | | | |
|
||||
v v | |
|
||||
+---------+ | |
|
||||
| ( ) HP| | |
|
||||
+---------+ | |
|
||||
| |
|
||||
bouton PTT : GPIO4 ----[ / ]---- GND <-------------+ |
|
||||
LED etat : GPIO2 ----[330]---->|---- GND <-----------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Pourquoi ce choix de broches
|
||||
|
||||
| Contrainte | Conséquence |
|
||||
|---|---|
|
||||
| **Broches de strapping** GPIO 0, 2, 5, 12, 15 | leur niveau au reset choisit le mode de démarrage → aucun signal audio dessus. GPIO 2 ne porte qu'une LED, en sortie seule. |
|
||||
| **GPIO 34-39 sont en entrée seule** | inutilisables pour SCK/WS (sorties d'horloge). |
|
||||
| **GPIO 6-11** | reliées à la mémoire flash interne → jamais utilisables. |
|
||||
| **Deux périphériques I2S séparés** | I2S0 pour le micro, I2S1 pour l'ampli. On ne partage **pas** les horloges : le micro tourne en 32 bits/slot et l'ampli en 16 bits, et surtout l'entrée et la sortie doivent pouvoir démarrer et s'arrêter indépendamment. Cinq fils au lieu de trois : c'est le prix de la simplicité logicielle. |
|
||||
| **GPIO 1 / 3 (TX0/RX0)** | utilisées par l'USB-série → interdites. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Réglages matériels du MAX98357A
|
||||
|
||||
### Broche `GAIN`
|
||||
|
||||
| Câblage de `GAIN` | Gain |
|
||||
|---|---|
|
||||
| direct à GND | 15 dB |
|
||||
| à GND via 100 kΩ | 12 dB |
|
||||
| **non connectée** | **9 dB** ← notre choix |
|
||||
| à Vin via 100 kΩ | 6 dB |
|
||||
| direct à Vin | 3 dB |
|
||||
|
||||
### Broche `SD` (shutdown + choix de canal)
|
||||
|
||||
La tension sur `SD` sélectionne le mode :
|
||||
|
||||
| Tension sur `SD` | Mode |
|
||||
|---|---|
|
||||
| < 0,16 V | ampli éteint |
|
||||
| 0,16 – 0,77 V | canal droit seul |
|
||||
| 0,77 – 1,4 V | canal gauche seul |
|
||||
| **> 1,4 V** | **moyenne (gauche + droite) / 2** ← par défaut |
|
||||
|
||||
Les cartes de type Adafruit tirent `SD` au + par 100 kΩ : laissée libre, la broche
|
||||
est donc au-dessus de 1,4 V et l'ampli fonctionne en mode moyenne.
|
||||
|
||||
Le firmware émet en **stéréo, le même échantillon sur les deux voies**
|
||||
(`AudioOutput`). La moyenne (gauche + droite) / 2 redonne donc exactement le
|
||||
signal : niveau correct, et une éventuelle inversion gauche/droite est sans effet.
|
||||
On n'a pas misé sur le comportement implicite d'un mode « mono » : c'est la leçon
|
||||
de l'étape 1, où une moitié de trame muette nous a longtemps égarés.
|
||||
|
||||
Pour couper le son par logiciel, on reliera plus tard `SD` à un GPIO
|
||||
(niveau bas = silence). Inutile avant l'étape 15.
|
||||
|
||||
---
|
||||
|
||||
## 5. Bilan de consommation
|
||||
|
||||
| Consommateur | Courant moyen | Crête |
|
||||
|---|---|---|
|
||||
| ESP32 (Wi-Fi actif) | ~120 mA | ~500 mA pendant l'émission radio |
|
||||
| INMP441 | 1,4 mA | — |
|
||||
| MAX98357A au repos | 2,4 mA | — |
|
||||
| MAX98357A à 3 W sur 4 Ω | ~670 mA | ~1,2 A sur les transitoires |
|
||||
| **Total au volume maximal** | **~0,8 A** | **> 1,5 A** |
|
||||
|
||||
Conséquences pratiques :
|
||||
|
||||
1. Une alimentation USB 5 V / 1 A **ne suffit pas** au volume maximal : l'ESP32
|
||||
redémarre (brown-out). Prévoir **5 V / 2 A**.
|
||||
2. Ajouter un condensateur **électrolytique 470 µF / 16 V** entre `Vin` et `GND`
|
||||
de l'ampli, au plus près de la carte : il fournit les crêtes que les fils de
|
||||
breadboard ne peuvent pas suivre. Types et valeurs limites : **§6**.
|
||||
3. Alternative propre : alimenter l'ampli par une source 5 V **externe**, en
|
||||
reliant sa masse à celle de l'ESP32 (**masse commune obligatoire**).
|
||||
|
||||
---
|
||||
|
||||
## 6. Condensateurs : types et valeurs
|
||||
|
||||
### 6.1 Les trois condensateurs du montage
|
||||
|
||||
| Rep. | Où | Rôle | Type exact |
|
||||
|---|---|---|---|
|
||||
| **C1** | `Vin` / `GND` du MAX98357A | réservoir d'énergie pour les crêtes du haut-parleur | électrolytique aluminium radial, **faible ESR**, 105 °C |
|
||||
| **C2** | `Vin` / `GND` du MAX98357A, collé à C1 | découplage haute fréquence (la classe D découpe à ~300 kHz) | céramique multicouche **X7R** ou X5R |
|
||||
| **C3** | GPIO 4 / `GND` (**optionnel**) | anti-rebond matériel du bouton | céramique multicouche **X7R** |
|
||||
|
||||
### 6.2 Valeurs minimale, typique et maximale
|
||||
|
||||
| Rep. | Mini | **Typique** | Maxi | Tension de service |
|
||||
|---|---|---|---|---|
|
||||
| **C1** | 100 µF<br>`1 × 10⁸ pF` | **470 µF**<br>`4,7 × 10⁸ pF` | 1 000 µF<br>`1 × 10⁹ pF` | ≥ 10 V, **16 V conseillé** |
|
||||
| **C2** | 10 nF<br>`10 000 pF` (code 103) | **100 nF**<br>`100 000 pF` (code **104**) | 1 µF<br>`1 000 000 pF` (code 105) | ≥ 25 V |
|
||||
| **C3** | 10 nF<br>`10 000 pF` (code 103) | **100 nF**<br>`100 000 pF` (code **104**) | 220 nF<br>`220 000 pF` (code 224) | ≥ 16 V |
|
||||
|
||||
Les bornes ne sont pas arbitraires :
|
||||
|
||||
- **C1 mini 100 µF** — la chute de tension pendant une crête vaut `ΔV = I × Δt / C`.
|
||||
Pour 1 A pendant 100 µs : 470 µF → 0,21 V (sans effet) ; 100 µF → 1,0 V (limite,
|
||||
l'ESP32 décroche vers 4,0 V en entrée de son régulateur) ; 47 µF → 2 V, redémarrage garanti.
|
||||
- **C1 maxi 1 000 µF** — au branchement, le condensateur vide est un court-circuit :
|
||||
`I = C × dV/dt`. Charger 1 000 µF à 5 V en 1 ms demande **5 A**, ce qui déclenche la
|
||||
protection du port USB ou du hub. Au-delà, il faut un circuit de pré-charge : hors sujet ici.
|
||||
- **C2** — au-dessus de ~1 MHz, un électrolytique se comporte comme une self : il ne
|
||||
découple plus rien. Sous 10 nF, la céramique ne stocke plus assez pour les fronts de
|
||||
commutation. Au-dessus de 1 µF, aucun gain et le boîtier devient inutilement gros.
|
||||
- **C3** — la constante de temps vaut `τ = R_pull-up × C`, avec le pull-up interne de
|
||||
l'ESP32 à ≈ 45 kΩ : 100 nF → τ = 4,5 ms, soit ~6 ms pour franchir le seuil logique.
|
||||
C'est bien en dessous des `BUTTON_DEBOUNCE_MS = 30 ms` du firmware. Avec 220 nF on
|
||||
atteint ~13 ms : encore acceptable. Au-delà, le filtre matériel et le filtre logiciel
|
||||
se cumulent et le bouton devient mou.
|
||||
|
||||
**C3 est facultatif** : l'anti-rebond est déjà fait en logiciel dans
|
||||
[PushButton.cpp](../firmware/src/PushButton.cpp). Ne l'ajoutez que si le bouton est au
|
||||
bout d'un fil long et capte du bruit. Dans ce cas, insérez aussi **100 Ω en série**
|
||||
entre le GPIO et le bouton : cette résistance limite le courant de décharge du
|
||||
condensateur dans le contact à chaque appui, ce qui préserve le bouton.
|
||||
|
||||
### 6.3 Lire le marquage — il est justement en picofarads
|
||||
|
||||
Les céramiques portent un **code à trois chiffres en pF** : deux chiffres significatifs,
|
||||
puis le nombre de zéros à ajouter.
|
||||
|
||||
| Code imprimé | picofarads | nanofarads | microfarads |
|
||||
|---|---|---|---|
|
||||
| `102` | 1 000 pF | 1 nF | 0,001 µF |
|
||||
| `103` | 10 000 pF | 10 nF | 0,01 µF |
|
||||
| **`104`** | **100 000 pF** | **100 nF** | **0,1 µF** |
|
||||
| `224` | 220 000 pF | 220 nF | 0,22 µF |
|
||||
| `105` | 1 000 000 pF | 1 000 nF | 1 µF |
|
||||
| `106` | 10 000 000 pF | 10 000 nF | 10 µF |
|
||||
|
||||
Une lettre suivante donne la tolérance : `J` = ±5 %, `K` = ±10 %, `M` = ±20 %.
|
||||
Sur un découplage, la tolérance n'a aucune importance : `K` ou `M` conviennent.
|
||||
|
||||
Les électrolytiques, eux, portent la valeur en clair (`470µF 16V`) et une **bande
|
||||
verticale marquant la borne négative**, en face de la patte la plus courte.
|
||||
|
||||
### 6.4 Pièges sur les condensateurs
|
||||
|
||||
1. **Polarité** — un électrolytique monté à l'envers chauffe, gonfle puis éclate en
|
||||
quelques secondes. La bande imprimée est le **−**, la patte longue est le **+**.
|
||||
Les céramiques, elles, ne sont pas polarisées.
|
||||
2. **Diélectrique** — refusez les `Y5V` et `Z5U` : ils perdent jusqu'à 80 % de leur
|
||||
capacité avec la température et la tension appliquée. **X7R** (ou X5R) pour le
|
||||
découplage, `C0G`/`NP0` seulement pour les petites valeurs.
|
||||
3. **Effet de la tension continue** — une céramique 10 µF / 6,3 V en boîtier 0603
|
||||
ne fait plus que 4 µF sous 5 V. C'est pourquoi C2 est spécifiée en **25 V minimum**.
|
||||
4. **ESR** — un 470 µF « general purpose » peut présenter 1 Ω de résistance série :
|
||||
inutile pour des crêtes de 1 A. Cherchez la mention **low ESR** ou **105 °C**
|
||||
(typiquement < 0,3 Ω).
|
||||
5. **Distance** — C1 et C2 à moins de 3 cm des broches `Vin` / `GND` de l'ampli.
|
||||
Au-delà, l'inductance des fils annule leur effet.
|
||||
6. **C1 et C2 ne se remplacent pas** : le gros stocke l'énergie, le petit évacue le
|
||||
haut du spectre. On met toujours les deux, en parallèle.
|
||||
|
||||
Les modules INMP441 et MAX98357A du commerce embarquent déjà leur découplage local
|
||||
(100 nF, et 10 µF côté ampli). C1 et C2 compensent **les fils de la platine d'essai**,
|
||||
pas un manque des modules.
|
||||
|
||||
---
|
||||
|
||||
## 7. Précautions de câblage
|
||||
|
||||
1. **Longueur des fils I2S** : 15 cm maximum. Au-delà, l'horloge se déforme et le
|
||||
son devient bruité.
|
||||
2. **Séparer** les fils du micro de ceux du haut-parleur : le courant du HP
|
||||
(jusqu'à 1 A commuté à 300 kHz) rayonne dans les fils du micro.
|
||||
3. **Masse commune** entre tous les modules, sans exception.
|
||||
4. Ne pas alimenter l'INMP441 en 5 V : il est prévu pour 1,8 à 3,3 V.
|
||||
5. Le micro est sensible aux vibrations : le fixer, ne pas le laisser pendre
|
||||
contre le boîtier du haut-parleur (effet Larsen mécanique).
|
||||
6. Sur breadboard, vérifier que les deux moitiés des rails d'alimentation sont
|
||||
bien reliées (beaucoup de breadboards coupent les rails au milieu).
|
||||
|
||||
---
|
||||
|
||||
## 8. Vérifications au multimètre, avant le premier démarrage
|
||||
|
||||
ESP32 **débranché**, en mode continuité puis en mode tension :
|
||||
|
||||
| # | Mesure | Attendu |
|
||||
|---|---|---|
|
||||
| 1 | continuité `INMP441 VDD` ↔ `ESP32 3V3` | passant |
|
||||
| 2 | continuité `INMP441 GND` ↔ `ESP32 GND` | passant |
|
||||
| 3 | continuité `INMP441 L/R` ↔ `GND` | passant |
|
||||
| 4 | continuité `INMP441 VDD` ↔ `GND` | **coupé** (sinon court-circuit) |
|
||||
| 5 | continuité `MAX98357A Vin` ↔ `ESP32 VIN` | passant |
|
||||
| 6 | continuité `MAX98357A −` ↔ `GND` | **coupé** |
|
||||
| 7 | continuité `GPIO 4` ↔ `GND`, bouton relâché | **coupé** |
|
||||
| 8 | continuité `GPIO 4` ↔ `GND`, bouton appuyé | passant |
|
||||
|
||||
### Continuité de la ligne de données
|
||||
|
||||
Le défaut le plus tenace de l'étape 1 est une ligne `SD` qui n'arrive pas. Testez
|
||||
en continuité, **carte hors tension**, et **sur la pastille du module**, jamais au
|
||||
bout du fil : une soudure sèche laisse passer le fil mais pas le signal.
|
||||
|
||||
| # | Mesure | Attendu |
|
||||
|---|---|---|
|
||||
| 8b | `GPIO 33` ↔ pastille `SD` du module | passant |
|
||||
| 8c | pastille `L/R` du module ↔ `GND` | passant |
|
||||
| 8d | `GPIO 33` ↔ `GND` | **coupé** |
|
||||
|
||||
Puis USB branché :
|
||||
|
||||
| # | Mesure | Attendu |
|
||||
|---|---|---|
|
||||
| 9 | tension `3V3` / `GND` | 3,2 à 3,4 V |
|
||||
| 10 | tension `VIN` / `GND` | 4,6 à 5,1 V |
|
||||
| 11 | tension `GPIO 4` / `GND`, bouton relâché | ≈ 3,3 V (pull-up interne) |
|
||||
| 12 | tension `GPIO 4` / `GND`, bouton appuyé | ≈ 0 V |
|
||||
|
||||
Le test 11 exige que le firmware soit déjà téléversé : le pull-up est activé par
|
||||
`pinMode(INPUT_PULLUP)`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Diagnostic rapide
|
||||
|
||||
| Symptôme | Cause la plus fréquente | Vérification |
|
||||
|---|---|---|
|
||||
| Auto-test : les deux moitiés « silence numerique » | le micro n'est pas cadencé ou n'émet rien | tensions sur les **pastilles du module** : `VDD` 3,3 V, `SCK` et `WS` ≈ 1,6 V |
|
||||
| Auto-test : « un bit de retard (Philips) » | le micro suit le cadrage Philips | aucune : le firmware bascule et revérifie |
|
||||
| Auto-test : « DECALE : bit de signe perdu » (23 bits) | cadrage faux, le premier bit déborde dans le mot précédent | aucune en MSB ; si ça persiste, envoyer l'analyse bit à bit |
|
||||
| Auto-test : « queue du mot non nulle » | bits parasites après les 24 bits utiles | vérifier `MIC_SD_PULLDOWN = true` |
|
||||
| Auto-test : « les DEUX moities portent des donnees » | `L/R` flottant, ou deux micros sur la ligne | continuité `L/R` ↔ GND sur la pastille |
|
||||
| Auto-test : « bruit de fond eleve » au repos | pièce bruyante, ou micro pas encore stabilisé | sans effet sur le cadrage ; juger sur l'enregistrement |
|
||||
| Ligne SD : « FLOTTE », horloges correctes | rien ne pilote GPIO 33 | continuité `SD` ↔ GPIO 33 sur la pastille |
|
||||
| Auto-test série : amplitude mesurable mais crête faible | simple question de gain | appliquer la valeur de `MIC_GAIN` conseillée par l'auto-test |
|
||||
| Crête à 0 %, silence total | `L/R` non relié à GND | test 3 |
|
||||
| Crête à 0 %, silence total | `SD` du micro sur la mauvaise broche | test de continuité vers GPIO 33 |
|
||||
| Bruit blanc continu | micro alimenté en 5 V | test 9 sur la broche `VDD` du micro |
|
||||
| Son très faible même en criant | `SCK` et `WS` inversés | inverser GPIO 25 et GPIO 26 |
|
||||
| Signal haché, craquements réguliers | fils I2S trop longs | raccourcir à 10 cm |
|
||||
| L'ESP32 redémarre quand le son sort | alimentation insuffisante | §5, points 1 et 2 |
|
||||
| Téléversement impossible | LED sur GPIO 2 qui perturbe le boot | retirer la LED externe, utiliser celle de la carte |
|
||||
| Le HP souffle ou vibre en permanence dès la mise sous tension | broches I2S de sortie flottantes : l'ampli amplifie du bruit | firmware ≥ étape 1 : `silenceAmplifier()` les force à 0. Si le bruit persiste pendant le boot, relier `SD` de l'ampli à `GND`, ou ne pas l'alimenter avant l'étape 2 |
|
||||
| Sifflement aigu permanent | masse commune absente entre ampli et ESP32 | §7, point 3 |
|
||||
|
||||
---
|
||||
|
||||
## 10. Récapitulatif des GPIO réservés
|
||||
|
||||
| GPIO | Usage | Étape |
|
||||
|---|---|---|
|
||||
| 2 | LED d'état | 1 |
|
||||
| 4 | bouton PTT | 1 |
|
||||
| 14 | MAX98357A `LRC` | 2 |
|
||||
| 22 | MAX98357A `DIN` | 2 |
|
||||
| 25 | INMP441 `SCK` | 1 |
|
||||
| 26 | INMP441 `WS` | 1 |
|
||||
| 27 | MAX98357A `BCLK` | 2 |
|
||||
| 33 | INMP441 `SD` | 1 |
|
||||
| 21 | LED de démonstration domotique (« la lumière » de la pièce) | 11 |
|
||||
|
||||
### LED de démonstration (étape 11, facultative)
|
||||
|
||||
```
|
||||
GPIO21 ──[ 330 Ω ]──►|── GND LED rouge ou verte : patte longue (anode) côté résistance
|
||||
```
|
||||
|
||||
Courant : (3,3 V − 2,0 V) / 330 Ω ≈ 4 mA, bien sous les 12 mA conseillés par broche.
|
||||
GPIO 21 est libre et sans rôle au démarrage (pas une broche de *strapping*). Elle
|
||||
figure « la lumière » de la pièce de la carte ; volets et porte sont simulés
|
||||
(état affiché sur la liaison série). Un module relais se brancherait au même endroit.
|
||||
Cette LED n'est pas dessinée sur `wiring.svg`.
|
||||
|
||||
Les valeurs sont définies une seule fois, dans
|
||||
[firmware/include/config.h](../firmware/include/config.h). Toute modification de
|
||||
câblage se fait dans ce fichier, jamais dans le code des classes.
|
||||
@@ -0,0 +1,158 @@
|
||||
# Broker Mosquitto — installation et vérification
|
||||
|
||||
Le broker (serveur MQTT) relaie tous les messages entre l'ESP32 et le serveur
|
||||
Python. Configuration unique : [mosquitto/voice.conf](../mosquitto/voice.conf).
|
||||
|
||||
---
|
||||
|
||||
## 1. Deux façons de le faire tourner
|
||||
|
||||
### Service Debian (Raspberry Pi, PC)
|
||||
|
||||
```bash
|
||||
make install-system # installe mosquitto et mosquitto-clients
|
||||
make mosquitto-config # copie voice.conf dans /etc/mosquitto/conf.d/ et redémarre
|
||||
```
|
||||
|
||||
### Conteneur Docker
|
||||
|
||||
Monter `voice.conf` **à la place** de `mosquitto.conf` du conteneur, et publier le
|
||||
port 1883 :
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mosquitto:
|
||||
image: eclipse-mosquitto:2.0
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 1883:1883
|
||||
volumes:
|
||||
- ./mosquitto/config:/mosquitto/config # contient voice.conf renommé mosquitto.conf
|
||||
```
|
||||
|
||||
Si le conteneur existe déjà :
|
||||
|
||||
```bash
|
||||
make mosquitto-docker MOSQ_DIR=~/srv/mosquitto MOSQ_COMPOSE=~/srv/docker-compose.mosquitto.yml
|
||||
```
|
||||
|
||||
La cible sauvegarde l'ancienne configuration (`mosquitto.conf.bak`), installe
|
||||
`voice.conf` avec le propriétaire du conteneur (uid 1883), relance le service et
|
||||
affiche les dernières lignes du journal. Le `sudo` est nécessaire : les fichiers
|
||||
appartiennent à l'utilisateur `mosquitto` du conteneur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Comptes et droits (étape 15)
|
||||
|
||||
Sans authentification, n'importe quel appareil du réseau local peut s'abonner à
|
||||
`voice/+/audio/stream` et **écouter le micro** en continu, ou publier une
|
||||
commande. Depuis l'étape 15, le broker exige un compte, et un fichier de droits
|
||||
(ACL, *Access Control List* : liste de qui peut lire ou écrire quel topic)
|
||||
limite chaque compte :
|
||||
|
||||
| Compte | Qui | Droits ([mosquitto/acl](../mosquitto/acl)) |
|
||||
|---|---|---|
|
||||
| `voice-server` | le serveur, et les cibles `make mqtt-*`, `tone-mqtt`, `play-mqtt` | lire et écrire `voice/#` et `home/#` |
|
||||
| `esp32-01` (= `DEVICE_ID`) | une carte | écrire **ses** `state`, `event`, `audio/in`, `audio/stream` ; lire **ses** `control`, `audio/out`, et `voice/server/status` |
|
||||
| `pc-bureau` (= `id` de l'agent) | un agent Linux (étape 15b) | écrire **ses** `agent/<id>/state` et `result` ; lire **ses** `agent/<id>/command` |
|
||||
|
||||
Une carte ne peut donc ni écouter une autre carte, ni publier sous son nom, ni
|
||||
envoyer de commande domotique. Vérifié sur un broker de test : connexion
|
||||
anonyme et mauvais mot de passe refusés, usurpation d'une autre carte jetée.
|
||||
|
||||
```bash
|
||||
make mqtt-user NAME=voice-server # mot de passe demandé deux fois, stocké haché
|
||||
make mqtt-user NAME=esp32-01 # un compte par carte, du nom de son DEVICE_ID
|
||||
make mosquitto-docker # installe voice.conf + acl + passwd, relance le broker
|
||||
```
|
||||
|
||||
Les mots de passe en clair vont dans `server/.env` (`MQTT_USERNAME`,
|
||||
`MQTT_PASSWORD`) et dans `firmware/include/secrets.h` (`MQTT_PASSWORD` ;
|
||||
`MQTT_USER` vide = `DEVICE_ID`). `mosquitto/passwd` ne contient que des
|
||||
empreintes (hachage : transformation à sens unique), et n'est pas versionné.
|
||||
|
||||
Le mot de passe circule encore **en clair** sur le réseau local : seul TLS
|
||||
(chiffrement, port 8883) l'empêcherait. C'est l'option de l'étape 15, non
|
||||
activée : sur un réseau Wi-Fi WPA2 domestique, l'écoute du trafic suppose déjà
|
||||
d'avoir la clé du Wi-Fi.
|
||||
|
||||
---
|
||||
|
||||
## 3. Pièges rencontrés
|
||||
|
||||
| Symptôme | Cause | Correctif |
|
||||
|---|---|---|
|
||||
| L'ESP32 ne se connecte pas, `mosquitto_sub` sur le PC fonctionne | Mosquitto 2.x sans `listener` explicite n'écoute que sur `localhost` | `listener 1883 0.0.0.0` |
|
||||
| Conteneur en état `restarting`, des centaines de redémarrages | deux lignes `listener 1883` : le second ne peut pas ouvrir le port (`Error: Address in use`) | **un seul** `listener` par port |
|
||||
| Le broker plante sans rien dire | `log_dest syslog` : dans un conteneur, il n'y a pas de syslog | `log_dest stdout`, puis `docker logs <conteneur>` |
|
||||
| `Note: It is recommended to replace message_size_limit` | option obsolète depuis Mosquitto 2.0 | `max_packet_size 8192` |
|
||||
| L'ESP32 affiche `mqtt : echec (code -2)` | connexion TCP refusée : broker arrêté, mauvaise IP, pare-feu | `make mqtt-watch` depuis le PC ; vérifier `MQTT_HOST` dans `secrets.h` |
|
||||
| Deux cartes se déconnectent l'une l'autre en boucle | même `DEVICE_ID`, donc même identifiant client MQTT | un `DEVICE_ID` différent par carte |
|
||||
| `connexion refusee par le broker : Not authorized` (serveur), `code 5` (ESP32) | compte absent de `passwd`, mot de passe différent, ou `MQTT_PASSWORD` vide | `make mqtt-user NAME=...`, puis `make mosquitto-docker` ; recopier le même mot de passe |
|
||||
| Tout est connecté, mais rien ne passe | droits : Mosquitto **jette en silence** une publication interdite et n'envoie rien à un abonnement interdit | nom d'utilisateur de la carte = son `DEVICE_ID` (la carte l'affiche au démarrage sinon) |
|
||||
| Un autre programme de la maison ne se connecte plus au broker | `allow_anonymous false` vaut pour **tous** les clients | lui créer un compte, et ses lignes dans `mosquitto/acl` |
|
||||
| `ACL pattern 'voice/server/status' does not contain '%c' or '%u'` au démarrage | avertissement : ce topic est commun à toutes les cartes, c'est voulu | rien à faire |
|
||||
|
||||
---
|
||||
|
||||
## 4. Vérifier le broker, sans ESP32
|
||||
|
||||
```bash
|
||||
make mqtt-watch # terminal 1 : tout ce qui passe sur voice/#
|
||||
make mqtt-control MSG='{"cmd":"ping"}' # terminal 2 : un message sur control
|
||||
```
|
||||
|
||||
Le terminal 1 doit afficher `voice/esp32-01/control {"cmd":"ping"}`.
|
||||
|
||||
Sans le paquet `mosquitto-clients`, ces cibles utilisent automatiquement les
|
||||
clients inclus dans l'image Docker `eclipse-mosquitto:2.0`.
|
||||
|
||||
---
|
||||
|
||||
## 5. État retenu et testament
|
||||
|
||||
| Topic | Qui publie | Quand | Retenu |
|
||||
|---|---|---|---|
|
||||
| `voice/esp32-01/state` `{"status":"online",...}` | l'ESP32 | à chaque connexion, puis toutes les 30 s | oui |
|
||||
| `voice/esp32-01/state` `{"status":"offline"}` | **le broker**, à la place de l'ESP32 | quand l'ESP32 disparaît sans prévenir | oui |
|
||||
| `voice/esp32-01/event` `{"event":"boot","reason":...}` | l'ESP32 | une fois par démarrage | non |
|
||||
|
||||
Messages publiés par le serveur (étape 10) :
|
||||
|
||||
| Topic | Qui publie | Quand | Retenu |
|
||||
|---|---|---|---|
|
||||
| `voice/esp32-01/transcript` `{"session":...,"utterances":[{"speaker":"Denis","text":...}]}` | le serveur (QoS 1) | après chaque question transcrite | non |
|
||||
| `home/<pièce>/<appareil>/set` `{"action":"close","by":"Denis","board":"esp32-01",...}` | le serveur (QoS 1), étape 11 | à chaque commande domotique | **non** : rejouée à un abonné tardif, elle ferait bouger un volet |
|
||||
| `voice/esp32-01/control` `{"cmd":"device","device":"light","action":"on"}` | le serveur, étape 11 | commande pour la pièce de la carte | non |
|
||||
| `voice/esp32-01/event` `{"event":"device",...,"ok":true,"state":"on"}` | l'ESP32, étape 11 | confirmation d'exécution | non |
|
||||
| `voice/esp32-01/control` `{"cmd":"listen","enabled":true}` | le serveur, étape 13 | connexion ou redémarrage de la carte ; `false` à l'arrêt du serveur | non |
|
||||
| `voice/esp32-01/audio/stream` (PCM binaire, QoS 0) | l'ESP32, étape 13 | en continu tant que l'écoute est active, sauf pendant une réponse ou un appui | non |
|
||||
| `voice/esp32-01/control` `{"cmd":"capture","active":true}` | le serveur, étape 13 | mot de réveil entendu (LED allumée) ; `false` à la fin de la commande | non |
|
||||
| `voice/server/status` `{"status":"online"}` | le serveur, étape 15 | à chaque connexion au broker | **oui** |
|
||||
| `voice/server/status` `{"status":"offline"}` | le serveur à l'arrêt, ou **le broker** (testament du serveur) s'il meurt | arrêt ou disparition du serveur : les cartes coupent leur micro | **oui** |
|
||||
| `agent/<machine>/state` `{"status":"online","actions":[...]}` | l'agent Linux, étape 15b ; `offline` par son testament | à sa connexion | **oui** |
|
||||
| `agent/<machine>/command` `{"action":"shutdown","id":...,"by":"Denis"}` | le serveur (QoS 1) | commande autorisée (et confirmée) | **non** : l'agent se connecte en session propre, rien n'est rejoué |
|
||||
| `agent/<machine>/result` `{"action":...,"ok":true,"code":0,"output":...}` | l'agent | après exécution | non |
|
||||
|
||||
- **Retenu** : le broker garde le dernier message du topic et le donne tout de
|
||||
suite à chaque nouvel abonné. Un serveur qui démarre après l'ESP32 connaît donc
|
||||
aussitôt son état.
|
||||
- **Testament** (*Last Will*) : confié au broker à la connexion. Si l'ESP32
|
||||
disparaît sans se déconnecter proprement, c'est le broker qui publie `offline`.
|
||||
|
||||
Délai du testament :
|
||||
|
||||
| Disparition | Le broker s'en aperçoit | `offline` publié après |
|
||||
|---|---|---|
|
||||
| ESP32 : coupure de courant, reset, plantage, perte du Wi-Fi | quand l'ESP32 cesse de répondre : la puce ne prévient jamais | 1,5 × `MQTT_KEEPALIVE_S` = **15 s** au plus |
|
||||
| client sur PC tué (`kill`, Ctrl-C) | immédiatement : le système d'exploitation ferme la connexion | < 1 s |
|
||||
|
||||
Après un simple reset, l'ESP32 se reconnecte en quelques secondes, souvent avant
|
||||
l'expiration du keepalive. Le broker remplace alors l'ancienne session par la
|
||||
nouvelle, et l'on peut voir passer un `offline` immédiatement suivi de `online`.
|
||||
Pour observer le testament seul, il faut **couper l'alimentation** et attendre.
|
||||
|
||||
La cause du redémarrage (`reason`) vaut `poweron`, `external` (broche EN),
|
||||
`software`, `panic` (plantage), `watchdog` ou **`brownout`** : chute de tension,
|
||||
typiquement l'ampli qui tire trop sur une alimentation USB faible.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 331 KiB |
+283
@@ -0,0 +1,283 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 1010" width="1400" height="1010" font-family="DejaVu Sans, Arial, Helvetica, sans-serif">
|
||||
<!-- Schéma de câblage : ESP32-WROOM-32 + INMP441 + MAX98357A + HP + bouton + LED -->
|
||||
<!-- Fond blanc explicite : le schéma reste lisible en thème sombre. -->
|
||||
<rect x="0" y="0" width="1400" height="1010" fill="#ffffff"/>
|
||||
|
||||
<style>
|
||||
.box { fill:#f7f7f4; stroke:#333333; stroke-width:2; }
|
||||
.title { font-size:17px; font-weight:bold; fill:#1a1a1a; }
|
||||
.sub { font-size:12px; fill:#555555; }
|
||||
.pin { font-size:12px; fill:#1a1a1a; }
|
||||
.pinused { font-size:12px; font-weight:bold; fill:#1a1a1a; }
|
||||
.lbl { font-size:12px; fill:#333333; }
|
||||
.tick { stroke:#999999; stroke-width:1.5; }
|
||||
.w { fill:none; stroke-width:2.4; stroke-linejoin:round; }
|
||||
.gnd { stroke:#333333; }
|
||||
.v33 { stroke:#cc2222; }
|
||||
.v5 { stroke:#e08214; }
|
||||
.clk { stroke:#1f6fd0; }
|
||||
.ws { stroke:#12855d; }
|
||||
.data { stroke:#8a3fc0; }
|
||||
.warn { font-size:12px; font-weight:bold; fill:#b30000; }
|
||||
</style>
|
||||
|
||||
<text x="30" y="40" class="title" font-size="22">Assistant vocal local — câblage complet</text>
|
||||
<text x="30" y="62" class="sub">ESP32-WROOM-32 · INMP441 (micro I2S) · MAX98357A (ampli I2S) · haut-parleur · bouton PTT · LED d'état</text>
|
||||
|
||||
<!-- =============================== ESP32 =============================== -->
|
||||
<text x="610" y="100" class="title" text-anchor="middle">ESP32-WROOM-32 (DevKit V1)</text>
|
||||
<rect x="480" y="110" width="260" height="590" rx="6" class="box"/>
|
||||
<text x="610" y="688" class="sub" text-anchor="middle">vue logique — repérez les numéros sérigraphiés</text>
|
||||
|
||||
<!-- colonne gauche -->
|
||||
<g class="pin">
|
||||
<text x="492" y="140">EN</text>
|
||||
<text x="492" y="178">GPIO 36</text>
|
||||
<text x="492" y="216">GPIO 39</text>
|
||||
<text x="492" y="254">GPIO 34</text>
|
||||
<text x="492" y="292">GPIO 35</text>
|
||||
<text x="492" y="330">GPIO 32</text>
|
||||
<text x="492" y="558">GPIO 12</text>
|
||||
<text x="492" y="596">GPIO 13</text>
|
||||
<text x="492" y="634">GND</text>
|
||||
</g>
|
||||
<g class="pinused">
|
||||
<text x="492" y="368">GPIO 33</text>
|
||||
<text x="492" y="406">GPIO 25</text>
|
||||
<text x="492" y="444">GPIO 26</text>
|
||||
<text x="492" y="482">GPIO 27</text>
|
||||
<text x="492" y="520">GPIO 14</text>
|
||||
<text x="492" y="672">VIN (5 V)</text>
|
||||
</g>
|
||||
|
||||
<!-- colonne droite -->
|
||||
<g class="pin" text-anchor="end">
|
||||
<text x="728" y="140">GPIO 23</text>
|
||||
<text x="728" y="216">TX0</text>
|
||||
<text x="728" y="254">RX0</text>
|
||||
<text x="728" y="292">GPIO 21</text>
|
||||
<text x="728" y="330">GPIO 19</text>
|
||||
<text x="728" y="368">GPIO 18</text>
|
||||
<text x="728" y="406">GPIO 5</text>
|
||||
<text x="728" y="444">GPIO 17</text>
|
||||
<text x="728" y="482">GPIO 16</text>
|
||||
<text x="728" y="596">GPIO 15</text>
|
||||
</g>
|
||||
<g class="pinused" text-anchor="end">
|
||||
<text x="728" y="178">GPIO 22</text>
|
||||
<text x="728" y="520">GPIO 4</text>
|
||||
<text x="728" y="558">GPIO 2</text>
|
||||
<text x="728" y="634">GND</text>
|
||||
<text x="728" y="672">3V3</text>
|
||||
</g>
|
||||
|
||||
<!-- ergots de broches -->
|
||||
<g class="tick">
|
||||
<line x1="470" y1="135" x2="480" y2="135"/><line x1="470" y1="173" x2="480" y2="173"/>
|
||||
<line x1="470" y1="211" x2="480" y2="211"/><line x1="470" y1="249" x2="480" y2="249"/>
|
||||
<line x1="470" y1="287" x2="480" y2="287"/><line x1="470" y1="325" x2="480" y2="325"/>
|
||||
<line x1="470" y1="363" x2="480" y2="363"/><line x1="470" y1="401" x2="480" y2="401"/>
|
||||
<line x1="470" y1="439" x2="480" y2="439"/><line x1="470" y1="477" x2="480" y2="477"/>
|
||||
<line x1="470" y1="515" x2="480" y2="515"/><line x1="470" y1="553" x2="480" y2="553"/>
|
||||
<line x1="470" y1="591" x2="480" y2="591"/><line x1="470" y1="629" x2="480" y2="629"/>
|
||||
<line x1="470" y1="667" x2="480" y2="667"/>
|
||||
<line x1="740" y1="135" x2="750" y2="135"/><line x1="740" y1="173" x2="750" y2="173"/>
|
||||
<line x1="740" y1="211" x2="750" y2="211"/><line x1="740" y1="249" x2="750" y2="249"/>
|
||||
<line x1="740" y1="287" x2="750" y2="287"/><line x1="740" y1="325" x2="750" y2="325"/>
|
||||
<line x1="740" y1="363" x2="750" y2="363"/><line x1="740" y1="401" x2="750" y2="401"/>
|
||||
<line x1="740" y1="439" x2="750" y2="439"/><line x1="740" y1="477" x2="750" y2="477"/>
|
||||
<line x1="740" y1="515" x2="750" y2="515"/><line x1="740" y1="553" x2="750" y2="553"/>
|
||||
<line x1="740" y1="591" x2="750" y2="591"/><line x1="740" y1="629" x2="750" y2="629"/>
|
||||
<line x1="740" y1="667" x2="750" y2="667"/>
|
||||
</g>
|
||||
|
||||
<!-- =============================== INMP441 =============================== -->
|
||||
<rect x="150" y="150" width="240" height="200" rx="6" class="box"/>
|
||||
<text x="270" y="178" class="title" text-anchor="middle" font-size="15">INMP441</text>
|
||||
<text x="270" y="196" class="sub" text-anchor="middle">micro I2S — entrée audio</text>
|
||||
<text x="270" y="214" class="warn" text-anchor="middle">3,3 V uniquement</text>
|
||||
<g class="pinused" text-anchor="end">
|
||||
<text x="378" y="240">SD</text>
|
||||
<text x="378" y="268">SCK</text>
|
||||
<text x="378" y="296">WS</text>
|
||||
</g>
|
||||
<g class="pinused">
|
||||
<text x="162" y="344">L/R</text>
|
||||
<text x="196" y="344">GND</text>
|
||||
<text x="236" y="344">VDD</text>
|
||||
</g>
|
||||
<g class="tick">
|
||||
<line x1="390" y1="236" x2="400" y2="236"/>
|
||||
<line x1="390" y1="264" x2="400" y2="264"/>
|
||||
<line x1="390" y1="292" x2="400" y2="292"/>
|
||||
<line x1="170" y1="350" x2="170" y2="360"/>
|
||||
<line x1="200" y1="350" x2="200" y2="360"/>
|
||||
<line x1="240" y1="350" x2="240" y2="360"/>
|
||||
</g>
|
||||
|
||||
<!-- fils du micro -->
|
||||
<polyline class="w data" points="390,236 455,236 455,363 470,363"/>
|
||||
<polyline class="w clk" points="390,264 440,264 440,401 470,401"/>
|
||||
<polyline class="w ws" points="390,292 425,292 425,439 470,439"/>
|
||||
|
||||
<polyline class="w gnd" points="170,350 170,790"/>
|
||||
<polyline class="w gnd" points="200,350 200,790"/>
|
||||
<polyline class="w v33" points="240,350 240,750"/>
|
||||
<text x="120" y="378" class="lbl" transform="rotate(-90 120 378)">L/R → GND (canal gauche)</text>
|
||||
|
||||
<!-- =============================== MAX98357A =============================== -->
|
||||
<rect x="880" y="380" width="260" height="240" rx="6" class="box"/>
|
||||
<text x="1010" y="408" class="title" text-anchor="middle" font-size="15">MAX98357A</text>
|
||||
<text x="1010" y="426" class="sub" text-anchor="middle">ampli classe D mono — sortie audio</text>
|
||||
<text x="1010" y="444" class="sub" text-anchor="middle">alimenté en 5 V</text>
|
||||
<g class="pinused">
|
||||
<text x="892" y="475">LRC</text>
|
||||
<text x="892" y="503">BCLK</text>
|
||||
<text x="892" y="531">DIN</text>
|
||||
</g>
|
||||
<g class="pin">
|
||||
<text x="898" y="600">GAIN</text>
|
||||
<text x="950" y="600">SD</text>
|
||||
<text x="996" y="600">GND</text>
|
||||
<text x="1050" y="600">Vin</text>
|
||||
</g>
|
||||
<g class="pinused" text-anchor="end">
|
||||
<text x="1128" y="475">+</text>
|
||||
<text x="1128" y="535">−</text>
|
||||
</g>
|
||||
<g class="tick">
|
||||
<line x1="870" y1="470" x2="880" y2="470"/>
|
||||
<line x1="870" y1="500" x2="880" y2="500"/>
|
||||
<line x1="870" y1="530" x2="880" y2="530"/>
|
||||
<line x1="920" y1="620" x2="920" y2="630"/>
|
||||
<line x1="970" y1="620" x2="970" y2="630"/>
|
||||
<line x1="1020" y1="620" x2="1020" y2="630"/>
|
||||
<line x1="1070" y1="620" x2="1070" y2="630"/>
|
||||
<line x1="1140" y1="470" x2="1150" y2="470"/>
|
||||
<line x1="1140" y1="530" x2="1150" y2="530"/>
|
||||
</g>
|
||||
|
||||
<!-- fils de l'ampli : LRC et BCLK contournent la carte par le bas -->
|
||||
<polyline class="w ws" points="470,515 430,515 430,715 860,715 860,470 880,470"/>
|
||||
<polyline class="w clk" points="470,477 415,477 415,730 845,730 845,500 880,500"/>
|
||||
<polyline class="w data" points="750,173 830,173 830,530 880,530"/>
|
||||
<text x="262" y="680" class="lbl" font-size="11">GPIO 14 → LRC (vert)</text>
|
||||
<text x="262" y="696" class="lbl" font-size="11">GPIO 27 → BCLK (bleu)</text>
|
||||
<text x="262" y="716" class="lbl" font-size="11">ces deux fils contournent la carte</text>
|
||||
<text x="760" y="166" class="lbl">GPIO 22 → DIN</text>
|
||||
|
||||
<!-- GAIN et SD laissés libres -->
|
||||
<text x="880" y="650" class="lbl" font-size="11">GAIN : NC → 9 dB</text>
|
||||
<text x="880" y="666" class="lbl" font-size="11">SD : NC → ampli actif</text>
|
||||
|
||||
<polyline class="w gnd" points="1020,620 1020,790"/>
|
||||
<polyline class="w v5" points="1070,620 1070,830"/>
|
||||
|
||||
<!-- découplage conseillé : C1 (réservoir) + C2 (haute fréquence) -->
|
||||
<g>
|
||||
<polyline class="w v5" points="1070,655 1290,655"/>
|
||||
<circle cx="1070" cy="655" r="4" fill="#333"/>
|
||||
|
||||
<!-- C1 : électrolytique polarisé -->
|
||||
<line x1="1180" y1="655" x2="1180" y2="660" stroke="#333" stroke-width="2"/>
|
||||
<line x1="1164" y1="660" x2="1196" y2="660" stroke="#333" stroke-width="3"/>
|
||||
<line x1="1164" y1="672" x2="1196" y2="672" stroke="#333" stroke-width="3"/>
|
||||
<polyline class="w gnd" points="1180,672 1180,790"/>
|
||||
<text x="1150" y="666" class="lbl" font-size="13">+</text>
|
||||
<text x="1202" y="650" class="pinused">C1</text>
|
||||
|
||||
<!-- C2 : céramique -->
|
||||
<line x1="1260" y1="655" x2="1260" y2="660" stroke="#333" stroke-width="2"/>
|
||||
<line x1="1244" y1="660" x2="1276" y2="660" stroke="#333" stroke-width="3"/>
|
||||
<line x1="1244" y1="672" x2="1276" y2="672" stroke="#333" stroke-width="3"/>
|
||||
<polyline class="w gnd" points="1260,672 1260,790"/>
|
||||
<text x="1282" y="650" class="pinused">C2</text>
|
||||
|
||||
<text x="1000" y="876" class="title" font-size="13">Découplage conseillé</text>
|
||||
<text x="1000" y="900" class="lbl">C1 = 470 µF / 16 V électrolytique, faible ESR</text>
|
||||
<text x="1000" y="920" class="lbl"> polarisé : la bande imprimée est le « − »</text>
|
||||
<text x="1000" y="940" class="lbl">C2 = 100 nF X7R céramique (code 104)</text>
|
||||
<text x="1000" y="960" class="lbl">les deux à moins de 3 cm des broches de l'ampli</text>
|
||||
</g>
|
||||
|
||||
<!-- =============================== haut-parleur =============================== -->
|
||||
<rect x="1210" y="440" width="130" height="120" rx="6" class="box"/>
|
||||
<text x="1275" y="478" class="title" text-anchor="middle" font-size="15">HP</text>
|
||||
<text x="1275" y="500" class="sub" text-anchor="middle">4 Ω / 3 W</text>
|
||||
<text x="1275" y="518" class="sub" text-anchor="middle">(ou 8 Ω / 2 W)</text>
|
||||
<line class="w gnd" x1="1150" y1="470" x2="1210" y2="470"/>
|
||||
<line class="w gnd" x1="1150" y1="530" x2="1210" y2="530"/>
|
||||
<text x="1152" y="462" class="lbl">+</text>
|
||||
<text x="1150" y="586" class="lbl" font-size="11">« − » jamais à la masse</text>
|
||||
|
||||
<!-- =============================== bouton PTT =============================== -->
|
||||
<rect x="900" y="150" width="160" height="56" rx="6" class="box"/>
|
||||
<text x="980" y="172" class="title" text-anchor="middle" font-size="14">Bouton PTT</text>
|
||||
<text x="980" y="192" class="sub" text-anchor="middle">pull-up interne</text>
|
||||
<polyline class="w gnd" points="750,515 800,515 800,177 900,177"/>
|
||||
<polyline class="w gnd" points="1060,177 1120,177 1120,225"/>
|
||||
<text x="756" y="508" class="lbl" font-size="11">→ bouton</text>
|
||||
<g stroke="#333333" stroke-width="2.4" fill="none">
|
||||
<line x1="1108" y1="225" x2="1132" y2="225"/>
|
||||
<line x1="1113" y1="231" x2="1127" y2="231"/>
|
||||
<line x1="1118" y1="237" x2="1122" y2="237"/>
|
||||
</g>
|
||||
<text x="1140" y="231" class="lbl">GND</text>
|
||||
|
||||
<!-- =============================== LED d'état =============================== -->
|
||||
<rect x="900" y="250" width="160" height="56" rx="6" class="box"/>
|
||||
<text x="980" y="272" class="title" text-anchor="middle" font-size="14">LED + 330 Ω</text>
|
||||
<text x="980" y="292" class="sub" text-anchor="middle">optionnelle (LED intégrée)</text>
|
||||
<polyline class="w gnd" points="750,553 815,553 815,277 900,277"/>
|
||||
<polyline class="w gnd" points="1060,277 1120,277 1120,325"/>
|
||||
<text x="756" y="546" class="lbl" font-size="11">→ LED</text>
|
||||
<g stroke="#333333" stroke-width="2.4" fill="none">
|
||||
<line x1="1108" y1="325" x2="1132" y2="325"/>
|
||||
<line x1="1113" y1="331" x2="1127" y2="331"/>
|
||||
<line x1="1118" y1="337" x2="1122" y2="337"/>
|
||||
</g>
|
||||
<text x="1140" y="331" class="lbl">GND</text>
|
||||
|
||||
<!-- =============================== rails =============================== -->
|
||||
<line class="w v33" x1="140" y1="750" x2="1340" y2="750"/>
|
||||
<line class="w gnd" x1="140" y1="790" x2="1340" y2="790"/>
|
||||
<line class="w v5" x1="140" y1="830" x2="1340" y2="830"/>
|
||||
<text x="140" y="744" class="lbl" fill="#cc2222">3,3 V</text>
|
||||
<text x="140" y="784" class="lbl">GND (masse commune)</text>
|
||||
<text x="140" y="824" class="lbl" fill="#e08214">5 V</text>
|
||||
|
||||
<!-- alimentations prélevées sur l'ESP32 -->
|
||||
<polyline class="w v33" points="750,667 800,667 800,750"/>
|
||||
<polyline class="w gnd" points="750,629 775,629 775,790"/>
|
||||
<polyline class="w v5" points="470,667 455,667 455,830"/>
|
||||
|
||||
<!-- points de connexion aux rails -->
|
||||
<g fill="#cc2222"><circle cx="800" cy="750" r="4"/><circle cx="240" cy="750" r="4"/></g>
|
||||
<g fill="#333333">
|
||||
<circle cx="775" cy="790" r="4"/><circle cx="170" cy="790" r="4"/>
|
||||
<circle cx="200" cy="790" r="4"/><circle cx="1020" cy="790" r="4"/>
|
||||
<circle cx="1180" cy="790" r="4"/><circle cx="1260" cy="790" r="4"/>
|
||||
</g>
|
||||
<g fill="#e08214"><circle cx="455" cy="830" r="4"/><circle cx="1070" cy="830" r="4"/></g>
|
||||
|
||||
<!-- =============================== légende =============================== -->
|
||||
<rect x="30" y="852" width="520" height="140" rx="6" fill="#ffffff" stroke="#bbbbbb" stroke-width="1.5"/>
|
||||
<text x="44" y="876" class="title" font-size="14">Légende</text>
|
||||
<g class="lbl">
|
||||
<line class="w v5" x1="44" y1="896" x2="80" y2="896"/><text x="88" y="900">5 V</text>
|
||||
<line class="w v33" x1="44" y1="918" x2="80" y2="918"/><text x="88" y="922">3,3 V</text>
|
||||
<line class="w gnd" x1="44" y1="940" x2="80" y2="940"/><text x="88" y="944">masse / logique</text>
|
||||
<line class="w clk" x1="230" y1="896" x2="266" y2="896"/><text x="274" y="900">horloge bit (SCK / BCLK)</text>
|
||||
<line class="w ws" x1="230" y1="918" x2="266" y2="918"/><text x="274" y="922">mot (WS / LRC)</text>
|
||||
<line class="w data" x1="230" y1="940" x2="266" y2="940"/><text x="274" y="944">données audio (SD / DIN)</text>
|
||||
</g>
|
||||
<circle cx="52" cy="964" r="4" fill="#333"/>
|
||||
<text x="88" y="968" class="lbl">connexion électrique — deux fils qui se croisent sans point ne sont pas reliés.</text>
|
||||
|
||||
<!-- =============================== avertissements =============================== -->
|
||||
<text x="580" y="876" class="warn">Masse commune obligatoire entre tous les modules.</text>
|
||||
<text x="580" y="900" class="lbl">Câblez hors tension. INMP441 en 3,3 V : le 5 V le détruit.</text>
|
||||
<text x="580" y="920" class="lbl">Fils I2S de 15 cm maximum, éloignés des fils du haut-parleur.</text>
|
||||
<text x="580" y="940" class="lbl">Alimentation 5 V / 2 A : l'ampli demande jusqu'à 1,2 A sur les crêtes.</text>
|
||||
<text x="580" y="960" class="lbl">Détails et vérifications : docs/BROCHAGE.md</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user