424 lines
20 KiB
Markdown
424 lines
20 KiB
Markdown
# Prompt pour Claude Code — Firmware TMS320F28027 « dual boost »
|
||
|
||
> Version 2 — brochage corrigé, constantes de calibration réelles.
|
||
> À coller dans Claude Code (CCS v21) après avoir ouvert le dépôt
|
||
> `TMS320F28027-dualboost`.
|
||
|
||
---
|
||
|
||
## 1. Contexte
|
||
|
||
Firmware d'une alimentation haute tension à deux étages boost en cascade,
|
||
pour préamplis à tubes (charge ~10-15 mA, modulée à fréquence audio).
|
||
|
||
- **MCU** : TMS320F28027, LQFP48 (PT), carte sur mesure
|
||
- **IDE** : Code Composer Studio v21 (Theia), compilateur C2000
|
||
- **Bibliothèque** : C2000Ware, headers **bitfield** (`DSP28x_Project.h`,
|
||
`F2802x_Device.h`) — **pas driverlib**
|
||
- **Sonde** : Olimex TMS320-XDS100-V3
|
||
- **Horloge** : **oscillateur interne INTOSC1 (10 MHz)**, PLL → SYSCLKOUT = 60 MHz
|
||
- **Dépôt** : `git@git.syoul.fr:alim-High-Volt-boost/TMS320F28027-dualboost.git`
|
||
|
||
Un ESP32-C3 (dépôt `ESP32-C3-dualboost`, déjà fonctionnel : OLED SSD1322
|
||
256x64 + serveur web) gère l'IHM. Protocole dans `docs/ESP32-UART.md` —
|
||
**source de vérité, ne rien inventer**.
|
||
|
||
Puissance par étage : MOSFET IPD60R360 (600 V), diode SiC STPSC406 (600 V/4 A),
|
||
inductance 47-100 µH. Sortie HT commutée par MOSFET N piloté par optocoupleur
|
||
photovoltaïque VOM1271 (~265-325 µs — coupure de sécurité lente, **pas** une
|
||
protection rapide).
|
||
|
||
---
|
||
|
||
## 2. Brochage définitif (LQFP48 PT)
|
||
|
||
### Entrées analogiques
|
||
|
||
| Signal | Broche | Fonction MCU | Rôle | Échelle |
|
||
|---|---|---|---|---|
|
||
| `V-Batt-adc` | 10 | ADCINA0 / **VREFHI** | VIN | 11,11 V/V (PE 36,7 V) |
|
||
| `I-Batt-adc` | 8 | ADCINA1 | IIN | 1,125 A/V (PE 3,71 A) |
|
||
| `I-shunt1-adc` | **9** | ADCINA2 / **COMP1A** / AIO2 | I1 + **protection étage 1** | 0,02 Ω × 30 → 1,667 A/V (PE 5,5 A) |
|
||
| `I-HV-adc` | 7 | ADCINA3 | IOUT | 16,67 mA/V (PE 55 mA) |
|
||
| `I-shunt2-adc` | **5** | ADCINA4 / **COMP2A** / AIO4 | I2 + **protection étage 2** | idem |
|
||
| `V-HV-adc` | **14** | ADCINB2 / AIO10 | VOUT | 178,6 V/V (PE 589 V) |
|
||
| `V-inter-adc` | **16** | ADCINB4 / AIO12 | V1 | 31,25 V/V (PE 103 V, V1max = 50 V → 1,6 V) |
|
||
| `Temp1` | 17 | ADCINB6 / AIO14 | NTC étage 1 | voir §5 |
|
||
| `Temp2` | 18 | ADCINB7 | NTC étage 2 | voir §5 |
|
||
| *libre* | 13 | ADCINB1 | — | |
|
||
| *libre* | 15 | ADCINB3 | — | |
|
||
|
||
**Points d'attention obligatoires :**
|
||
|
||
1. Les broches 5, 9, 14, 16, 17 sont des **AIO** (AIO4, AIO2, AIO10, AIO12,
|
||
AIO14) et sont en **mode numérique par défaut au reset**. Sans écriture
|
||
explicite dans `AIOMUX1` (valeur du champ = **2**), ni l'ADC ni les
|
||
comparateurs ne voient le signal. **À faire en tout début d'init.**
|
||
2. **Les shunts sont obligatoirement sur les entrées `COMPxA` (pins 9 et 5).**
|
||
Contrainte de silicium : `COMPxA` est câblée en dur sur l'entrée
|
||
non-inverseuse (+) du comparateur ; `COMPxB` n'existe que comme
|
||
alternative au DAC sur l'entrée inverseuse (−). Il n'y a aucun mux
|
||
permettant de les échanger. Seules les entrées A sont donc utilisées,
|
||
avec `COMPSOURCE = 0` (référence = DAC interne).
|
||
3. Les broches 9 et 5 servent **simultanément** d'entrée ADC et d'entrée
|
||
comparateur — c'est la même broche physique, le signal alimente les deux
|
||
chemins en parallèle. Pas de conflit, `I1`/`I2` restent disponibles en
|
||
télémétrie.
|
||
4. `VREFHI` est partagé avec `ADCINA0`, utilisé pour VIN → **référence ADC
|
||
interne obligatoire** (`ADCCTL1.bit.ADCREFSEL = 0`, pleine échelle 3,3 V).
|
||
Conséquences documentées : erreur de gain ±60 LSB, tempco −50 ppm/°C.
|
||
Le signal sur ADCINA0 ne doit jamais dépasser VDDA.
|
||
5. `V-inter` : pleine échelle 103 V pour une tension intermédiaire maximale
|
||
de **50 V** → ~48 % de la plage ADC utilisée, ~2000 codes sur la plage
|
||
utile. Pas de saturation, diviseur conservé tel quel.
|
||
|
||
### Répartition des tensions
|
||
|
||
- **Étage 1** : 10 V → **50 V max** (D ≈ 0,8)
|
||
- **Étage 2** : 50 V → **400 V max** (D ≈ 0,875), consigne programmable
|
||
200 / 250 / … / 400 V
|
||
|
||
### Entrées / sorties numériques
|
||
|
||
| Signal | Broche | Fonction MCU | Sens |
|
||
|---|---|---|---|
|
||
| `UART-RX` | 48 | GPIO28 / SCIRXDA | Entrée (← ESP32 GPIO7) |
|
||
| `UART-TX` | 1 | GPIO29 / SCITXDA | Sortie (→ ESP32 GPIO6) |
|
||
| `Stage1-PWM` | 29 | GPIO0 / **EPWM1A** | Sortie PWM étage 1 (HRPWM possible) |
|
||
| `Stage1-default` | 28 | GPIO1 / **COMP1OUT** | Sortie comparateur 1 |
|
||
| `Stage2-PWM` | 37 | GPIO2 / **EPWM2A** | Sortie PWM étage 2 (HRPWM possible) |
|
||
| `Stage2-default` | 38 | GPIO3 / **COMP2OUT** | Sortie comparateur 2 |
|
||
| `Stage1-EN` | 27 | GPIO16 | Sortie — enable logiciel étage 1 |
|
||
| `Stage2-EN` | 26 | GPIO17 | Sortie — enable logiciel étage 2 |
|
||
| `HV_EN` | 31 | GPIO32 | Sortie — commande sortie HT (VOM1271) |
|
||
| LED bleue | 47 | GPIO12 | Sortie |
|
||
| LED rouge | 35 | GPIO33 | Sortie |
|
||
| JTAG | 20-23 | TDI/TMS/TDO/TCK | **Ne pas reconfigurer en GPIO** |
|
||
|
||
Les LEDs sont câblées avec une résistance de 1 kΩ vers le 3,3 V → **logique
|
||
probablement inversée** (LED allumée quand le GPIO est bas) : à vérifier au
|
||
premier test et à encapsuler dans `led_set()` pour ne pas polluer le reste
|
||
du code.
|
||
|
||
**Aucune broche TZ externe n'est disponible** (GPIO12 = TZ1 → LED, GPIO16/17
|
||
= TZ2/TZ3 → Stage-EN). Tous les trips passent par le Digital Compare interne
|
||
depuis `COMPxOUT`. Conséquence assumée : pas de possibilité d'ajouter un trip
|
||
externe (arrêt d'urgence, thermostat matériel) sans reprendre le routage.
|
||
|
||
### Logique de sécurité câblée (hors MCU)
|
||
|
||
Deux portes ET 74HVC1G08 (IC8, IC9), une par étage :
|
||
|
||
```
|
||
COMPxOUT (Stagex-default, CMPINV=1 : 1=OK, 0=défaut) ──┐
|
||
├─ AND ─→ PWMx-EN (driver)
|
||
GPIO Stagex-EN (logiciel : 1=autorisé, 0=inhibé) ──┘
|
||
```
|
||
|
||
Les drivers sont **actifs à l'état haut**, d'où `CMPINV = 1` sur les deux
|
||
comparateurs. Le logiciel peut inhiber en plus, **jamais** outrepasser la
|
||
protection matérielle.
|
||
|
||
---
|
||
|
||
## 3. Horloge — contraintes liées à l'oscillateur interne
|
||
|
||
Pas de quartz : INTOSC1 (10 MHz nominal). PLL pour 60 MHz :
|
||
`PLLCR = 12`, `DIVSEL = /2` → 10 × 12 / 2 = 60 MHz.
|
||
|
||
**Obligatoire** : quand la source est l'oscillateur interne, `PLLLOCKPRD`
|
||
doit être écrit avec **10000 minimum** (sinon le verrouillage PLL est mal
|
||
temporisé).
|
||
|
||
**Dérive à documenter et à gérer** : 3,03 à 4,85 kHz/°C, plage 9,6-10,6 MHz
|
||
sur −40/+125 °C, soit ~2 % sur 40 °C d'échauffement. Impacts :
|
||
|
||
- **UART fixé à 57600 bauds** (au lieu de 115200) pour élargir la marge de
|
||
tolérance sur le timing des trames. Côté ESP32, `Serial1.begin(57600, ...)`
|
||
doit être mis à jour en conséquence.
|
||
- Fréquence de découpage réelle à ±2 % → `FREQ1`/`FREQ2` en télémétrie sont
|
||
indicatifs, à annoter comme tels.
|
||
- Prévoir un point d'accroche (fonction vide + commentaire) pour ajouter plus
|
||
tard la compensation d'oscillateur via le capteur de température interne
|
||
(voir *Oscillator Compensation Guide* + code C2000Ware).
|
||
|
||
---
|
||
|
||
## 4. Architecture logicielle demandée
|
||
|
||
```
|
||
src/
|
||
main.c boucle principale, ordonnancement
|
||
bsp_clock.c/h InitSysCtrl, INTOSC1 + PLL 60 MHz, PLLLOCKPRD, watchdog
|
||
bsp_gpio.c/h mux GPIO, AIOMUX1, LEDs, HV_EN, StageX-EN
|
||
safety.c/h comparateurs + DAC, Digital Compare, Trip Zone, EMUSTOP
|
||
pwm.c/h init ePWM1/ePWM2, duty, fréquence (HRPWM plus tard)
|
||
adc.c/h init ADC (réf interne), SOC déclenché par ePWM, lecture brute
|
||
measure.c/h conversion brut -> unités physiques (V, A, °C)
|
||
control.c/h régulation — SQUELETTE UNIQUEMENT pour l'instant
|
||
uart_link.c/h SCI-A 57600 8N1, trames $T,...*XX et $C,...*XX
|
||
calib.h TOUTES les constantes matérielles, rien ailleurs
|
||
protocol.h tags, structures Telemetry / CommandState
|
||
docs/
|
||
ESP32-UART.md protocole (copié depuis le dépôt ESP32)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Constantes de calibration (`calib.h`)
|
||
|
||
Aucune de ces valeurs ne doit apparaître ailleurs que dans ce header.
|
||
|
||
### Tensions et courants
|
||
|
||
| Grandeur | Relation | Coefficient |
|
||
|---|---|---|
|
||
| VIN | 1,8 V @ 20 V | `VIN = Vadc × 11,111` |
|
||
| IIN | 2,4 V @ 2,7 A | `IIN = Vadc × 1,125` |
|
||
| V1 (inter) | 3,2 V @ 100 V | `V1 = Vadc × 31,25` |
|
||
| VOUT | 2,8 V @ 500 V | `VOUT = Vadc × 178,571` |
|
||
| IOUT | 3,0 V @ 50 mA | `IOUT = Vadc × 0,016667` (A) |
|
||
| I1, I2 | shunt 0,02 Ω, gain ×30 | `I = Vadc / 0,6 = Vadc × 1,6667` |
|
||
|
||
Conversion brut → volts : `Vadc = raw × 3.3f / 4096.0f` (référence interne).
|
||
|
||
### Seuil de protection (identique sur les deux étages)
|
||
|
||
- Seuil : **3 A** → `Vadc = 3 × 0,02 × 30 = 1,8 V`
|
||
- Code DAC 10 bits : `round(1.8 / 3.3 × 1023)` = **558**
|
||
- Marges connues : gain DAC −1,5 %, offset DAC 10 mV, offset comparateur
|
||
±5 mV, hystérésis 35 mV (≈ 58 mA ramenés au courant) → précision réelle du
|
||
seuil de l'ordre de ±2 %, largement suffisant face à la marge des composants.
|
||
- Temps de réponse comparateur → Trip Zone : 30 ns (asynchrone).
|
||
- Définir le seuil en **ampères** dans `calib.h`, et calculer le code DAC par
|
||
macro — ne jamais écrire 558 en dur.
|
||
|
||
### NTC (B57451V5103J062, boîtier 0805)
|
||
|
||
Montage : `3,3 V — NTC 10 k — R 10 k — 0 V`, mesure au point milieu.
|
||
R25 = 10 kΩ, B25/100 = 4000 K ±3 %.
|
||
|
||
```
|
||
R_ntc = R_fixe × Vadc / (3.3 - Vadc)
|
||
T(K) = 1 / ( 1/298.15 + ln(R_ntc / 10000) / 4000 )
|
||
```
|
||
|
||
Points de repère attendus : 0,75 V à 0 °C · 1,65 V à 25 °C · 2,94 V à 80 °C ·
|
||
3,09 V à 100 °C. La tension **monte** avec la température. Sensibilité vers
|
||
100 °C : ~7,7 mV/°C, soit ~10 LSB/°C — suffisant pour de la surveillance.
|
||
La tolérance ±3 % sur B donne ~±2 °C d'erreur vers 100 °C sans calibration
|
||
individuelle : acceptable pour de la protection thermique, pas pour de la
|
||
mesure de précision. À documenter.
|
||
|
||
Résistance fixe confirmée à **10 kΩ** (pont 10 k NTC / 10 k).
|
||
|
||
---
|
||
|
||
## 6. Étapes d'implémentation (un commit par étape)
|
||
|
||
### Étape 1 — Squelette + « hello LED »
|
||
|
||
- Projet CCS F28027, fichier `.cmd` Flash
|
||
- `InitSysCtrl()` adapté : INTOSC1, `PLLLOCKPRD = 10000`, PLLCR 12, DIVSEL /2
|
||
- Watchdog désactivé au début (à réactiver plus tard)
|
||
- Clignotement LED pour valider compilation + flash + XDS100v3
|
||
|
||
**Critère** : LED à 1 Hz, compilation sans warning, SYSCLKOUT vérifié à 60 MHz
|
||
(sortie XCLKOUT ou mesure d'un timer).
|
||
|
||
### Étape 2 — Sécurité (AVANT toute génération PWM)
|
||
|
||
Aucun PWM ne doit sortir tant que les protections ne sont pas armées **et
|
||
testées**.
|
||
|
||
1. `AIOMUX1` : basculer AIO2, AIO4, AIO10, AIO12, AIO14 en mode analogique
|
||
(valeur du champ = **2**).
|
||
2. **Horloges de module** : `PCLKCR3.bit.COMP1ENCLK = 1` et `COMP2ENCLK = 1`,
|
||
sinon `COMPSTS` ne se met jamais à jour.
|
||
3. **Comparateurs COMP1 / COMP2** (shunt sur l'entrée A, DAC en référence) :
|
||
- `COMPCTL.bit.COMPDACEN = 1` — **sans ça le bloc reste éteint**
|
||
- `COMPCTL.bit.COMPSOURCE = 0` (entrée inverseuse = DAC interne)
|
||
- `DACVAL.bit.DACVAL` = code du seuil 3 A. Formule TI :
|
||
`V = DACVAL × (VDDA − VSSA) / 1023` → **1023, pas 4096**.
|
||
Calculé par macro depuis `SAFETY_ISHUNT_THRESHOLD_A`, jamais en dur.
|
||
- `COMPCTL.bit.CMPINV = 1` (driver actif haut : sortie 1 = OK, 0 = défaut)
|
||
- `COMPCTL.bit.SYNCSEL = 0` (**asynchrone**) — c'est ce qui donne les 30 ns
|
||
de temps de réponse vers le Trip Zone. `QUALSEL` n'a d'effet qu'en mode
|
||
synchrone, qui ajoute de la latence : n'activer la qualification qu'après
|
||
avoir observé le bruit réel au scope, jamais par précaution a priori.
|
||
- Hystérésis d'entrée activée par défaut (~100 kΩ de contre-réaction,
|
||
35 mV) : compatible avec la sortie basse impédance de l'ampli.
|
||
`COMPHYSTCTL` (module ADC) permet de la désactiver si besoin.
|
||
- Sorties routées : GPIO1 (COMP1OUT, mux 3) et GPIO3 (COMP2OUT, mux 3)
|
||
4. **Trip Zone via Digital Compare**
|
||
- `DCTRIPSEL.bit.DCAHCOMPSEL` = COMP1OUT (code `1000b`) pour ePWM1,
|
||
COMP2OUT (`1001b`) pour ePWM2
|
||
- `TZDCSEL.bit.DCAEVT1` : configurer l'événement sur DCAH bas
|
||
- `TZSEL.bit.DCAEVT1 = 1` → **one-shot** (latché), pas cycle-by-cycle
|
||
- `TZCTL.bit.TZA = TZ_FORCE_LO`
|
||
5. **TZ6 = EMUSTOP** sur ePWM1 et ePWM2 :
|
||
```c
|
||
EPwm1Regs.TZSEL.bit.OSHT6 = 1;
|
||
EPwm1Regs.TZCTL.bit.TZA = TZ_FORCE_LO;
|
||
```
|
||
Le signal `EMUSTOP` du CPU **existe bien** et est câblé en dur sur TZ6 sur
|
||
cette famille (TRM SPRUI09A §3.2.7) ; il n'y a simplement pas de macro
|
||
nommée `EMUSTOP` dans les headers, on écrit directement `OSHT6`.
|
||
Indispensable : sans ça, un breakpoint posé pendant que le MOSFET conduit
|
||
laisse l'inductance se charger sans limite.
|
||
6. **`TBCTL.bit.FREE_SOFT = 0`** sur les deux ePWM, **en plus et non à la
|
||
place** du point 5. Attention : `FREE_SOFT` gèle seulement le compteur de
|
||
base de temps — l'Action Qualifier a déjà positionné la sortie, qui reste
|
||
figée dans son dernier état. Si le CPU s'arrête pendant le temps de
|
||
conduction, **la broche reste haute**. Seul TZ6 + `TZ_FORCE_LO` garantit
|
||
la mise à l'état bas.
|
||
7. **`EPWMx_TZINT`** : diagnostic logiciel uniquement (log, LED rouge,
|
||
notification ESP32). La coupure est déjà faite en matériel.
|
||
8. API : `safety_get_fault_flags()`, `safety_clear_faults()` (écriture
|
||
`TZCLR[OST]`, **jamais appelée automatiquement**).
|
||
9. **Test** : `TZFRC[OSHT]` pour forcer un trip logiciel, sans provoquer de
|
||
vrai court-circuit.
|
||
|
||
**Critère** : `TZFRC` force les deux sorties à 0 et lève le flag ; un
|
||
breakpoint coupe le PWM ; le flag ne se réarme pas seul.
|
||
|
||
### Étape 3 — GPIO de commande, état sûr au reset
|
||
|
||
- `HV_EN`, `Stage1-EN`, `Stage2-EN` à 0 **avant toute autre configuration**
|
||
- ⚠️ **L'état au reset n'est PAS fail-safe** : GPIO1 et GPIO3 (COMPxOUT) sont
|
||
des broches à fonction PWM, dont **les pull-ups ne sont pas activées au
|
||
reset** → elles flottent. GPIO16/17 (Stage-EN) ne sont pas des broches PWM
|
||
→ **pull-ups activées** → état haut. Résultat : à la mise sous tension, une
|
||
entrée de chaque porte ET flotte et l'autre est à 1 → **sortie
|
||
indéterminée, le driver peut être validé avant que le firmware ne tourne**.
|
||
- Correctif **matériel obligatoire** : pull-down 10 kΩ sur les deux entrées
|
||
de chaque porte ET, et sur les lignes PWM vers les drivers. Le firmware
|
||
ne peut rien pour la fenêtre pré-boot.
|
||
- Correctif logiciel complémentaire : désactiver les pull-ups internes de
|
||
GPIO16/17 via `GPAPUD` dès l'init.
|
||
- LED rouge = défaut latché, LED bleue = fonctionnement nominal
|
||
- Encapsuler la polarité des LED dans `led_set()`
|
||
|
||
### Étape 4 — ADC
|
||
|
||
- Référence **interne** (`ADCREFSEL = 0`), `Device_cal()` appelé
|
||
- 9 canaux (§2), **SOC déclenché par ePWM**, jamais en free-run :
|
||
échantillonner à un instant stable, loin des fronts de commutation
|
||
- ISR `ADCINT1` courte : stockage des valeurs brutes, rien de plus
|
||
- Moyenne glissante côté `measure.c` pour la télémétrie. La protection rapide
|
||
ne passe **pas** par l'ADC.
|
||
|
||
### Étape 5 — Conversion physique (`measure.c`)
|
||
|
||
Implémenter les relations du §5. Signature du type
|
||
`float measure_vin(uint16_t raw)`, unités documentées dans les prototypes.
|
||
|
||
### Étape 6 — PWM
|
||
|
||
- **ePWM1** → étage 1 (EPWM1A, GPIO0) · **ePWM2** → étage 2 (EPWM2A, GPIO2)
|
||
- Mode up-count, TBCLK = SYSCLKOUT = 60 MHz
|
||
- `TBPRD = 60e6 / Fpwm - 1` (599 à 100 kHz, 299 à 200 kHz)
|
||
- **Fréquences par étage : À CONFIRMER**
|
||
- **Duty de départ = 0 %**, puis rampe logicielle montante (soft-start),
|
||
indépendante de la régulation. Ne jamais démarrer au duty nominal : le
|
||
condensateur de sortie vide provoquerait un appel de courant destructeur.
|
||
|
||
> **Important — un boost à 0 % de duty ne donne pas 0 V en sortie.** Le chemin
|
||
> `Vin → L → diode → Cout` reste passant en permanence. Avec les deux étages à
|
||
> 0 %, la sortie HT est déjà à ~10 V ; si l'étage 1 régule à 50 V pendant que
|
||
> l'étage 2 est à 0 %, la sortie est à **50 V**. Le seul organe qui isole
|
||
> réellement la charge est `HV_EN` (VOM1271). Conséquence pour le firmware :
|
||
> toute séquence d'arrêt, de mise en sécurité ou de timeout UART doit couper
|
||
> `HV_EN` **en plus** d'inhiber les PWM, jamais seulement les PWM.
|
||
- API : `pwm_set_duty(stage, float duty_0_1)`, `pwm_set_freq(stage, hz)`,
|
||
`pwm_enable(stage, bool)`
|
||
- **HRPWM : ne pas l'implémenter maintenant**, mais structurer `pwm.c` pour
|
||
l'accueillir. Notes à consigner en commentaire :
|
||
- disponible uniquement sur les sorties **EPWMxA** → les deux étages sont
|
||
compatibles tels que routés
|
||
- SYSCLKOUT ≥ 50 MHz requis (OK à 60), MEP 150-310 ps, SFO obligatoire
|
||
- **limitation de 3 cycles SYSCLK** sur le rapport cyclique : à 200 kHz,
|
||
duty min 0,67 % et max 99 % — à confronter aux points de fonctionnement
|
||
- à 100 kHz sans HRPWM : 600 pas ≈ 9,2 bits, risque de limit cycling en
|
||
boucle fermée
|
||
|
||
### Étape 7 — Liaison UART
|
||
|
||
Conforme à `docs/ESP32-UART.md`, avec **57600 bauds 8N1** (et non 115200 —
|
||
mettre à jour le document et le firmware ESP32).
|
||
|
||
- SCI-A, GPIO28 (RX) / GPIO29 (TX)
|
||
- Émission `$T,...*XX` toutes les **200-500 ms** (l'ESP32 déclare la liaison
|
||
perdue au-delà de 2 s)
|
||
- Réception `$C,HT=x,PWM1=x,PWM2=x*XX` toutes les 500 ms
|
||
- Checksum **XOR** entre `$` et `*`, format `%02X` **majuscules** (sinon rejet
|
||
silencieux côté ESP32), terminaison `\n`, ligne ≤ 160 caractères
|
||
- Réception par ISR + buffer circulaire, **parsing dans la boucle principale**
|
||
- Trame au checksum invalide : ignorée silencieusement
|
||
- **Timeout côté TMS320** : sans trame `$C` valide depuis > 2 s → retour en
|
||
état sûr (PWM inhibés, HT coupée). La sécurité ne dépend jamais de l'ESP32.
|
||
- Vérifier le support `%f` du compilateur C28x dans `sprintf` ; si coût trop
|
||
élevé, formater les flottants manuellement (entier + décimales)
|
||
|
||
Champs : `FREQ1 FREQ2 DUTY1 DUTY2 VIN IIN V1 I1 T1 VOUT I2 T2 IOUT`
|
||
|
||
### Étape 8 — Régulation : squelette seulement
|
||
|
||
**Aucune régulation active à ce stade.** Le PWM reste à sa valeur de départ.
|
||
|
||
```c
|
||
typedef struct {
|
||
float setpoint; // consigne (V)
|
||
float measured;
|
||
float duty; // 0..1
|
||
float duty_min, duty_max;
|
||
bool enabled;
|
||
} control_stage_t;
|
||
|
||
void control_init(void);
|
||
void control_set_setpoint(int stage, float volts);
|
||
float control_update(int stage, float measured, float dt); // renvoie duty inchangé
|
||
```
|
||
|
||
Prévoir l'emplacement d'appel cadencé (`dt` constant) dans l'ISR ADC ou PWM.
|
||
Documenter en commentaire : le boost à fort gain présente un **zéro dans le
|
||
demi-plan droit** qui limite la bande passante atteignable ; la charge
|
||
(~10-15 mA, modulée à fréquence audio) impose surtout un bon **PSRR en bande
|
||
audio** ; une structure ADRC ou un PI cascadé sera évalué ensuite.
|
||
|
||
---
|
||
|
||
## 7. Règles
|
||
|
||
- **Headers bitfield uniquement**, pas de driverlib, pas de mélange sur un
|
||
même périphérique
|
||
- `EALLOW`/`EDIS` autour de tous les registres protégés (TZSEL, TZCTL, TZEINT,
|
||
TZCLR, TZFRC, HRCNFG, GPxMUX, AIOMUX1, INTOSCnTRIM, table des vecteurs PIE…)
|
||
- Aucune valeur magique : tout dans `calib.h`, commenté avec son origine
|
||
- ISR courtes : pas de `sprintf`, pas de flottant lourd, pas d'attente
|
||
- Ordre d'init strict : **GPIO en état sûr → AIOMUX1 → horloge → sécurité →
|
||
ADC → UART → PWM en dernier**
|
||
- Commits atomiques, un par étape
|
||
|
||
## 8. Interdits
|
||
|
||
- Activer le PWM avant que l'étape 2 soit testée
|
||
- Effacer automatiquement un flag de défaut latché
|
||
- Faire dépendre une protection du CPU, de l'ADC ou de l'UART
|
||
- Implémenter la régulation en boucle fermée maintenant
|
||
- Toucher aux broches JTAG (20-23)
|
||
- Inventer le protocole UART
|
||
|
||
## 9. Points encore ouverts
|
||
|
||
1. Fréquence de découpage par étage (100 ou 200 kHz)
|
||
2. Polarité réelle des LED (à confirmer au premier test)
|
||
3. Valeur d'inductance retenue par étage (47 ou 100 µH) — influe sur le mode
|
||
CCM/DCM et sur la vitesse de montée d'un courant de défaut
|
||
|
||
## 10. Première action attendue
|
||
|
||
Avant d'écrire du code : lire le dépôt, lister l'existant, **poser les
|
||
questions sur les points du §9**, puis proposer un plan et attendre validation
|
||
avant de commencer l'étape 1.
|