CORRECTIF CRITIQUE -- reception UART cassee (uart_link.c)
Le decodage du checksum utilisait strtol sur s_line, qui n'est JAMAIS
terminee par un '\0'. strtol lisait donc au-dela de la trame, dans les
residus de la ligne precedente.
Aggravant, specifique au C28x : uint8_t y fait 16 bits (pas d'adressage
par octet), donc le cast (uint8_t) ne tronquait rien. Un "7D" suivi d'un
"7D" residuel donnait 0x7D7D = 32125, conserve tel quel, et TOUTE trame
etait rejetee. Sur une architecture a octets le cast aurait masque le
probleme et le bug serait passe inapercu.
Constate sur cible : cs_calc = 0x7D (correct), cs_recv = 0x7D7D.
Consequence visible : plus aucune commande $C acceptee, donc timeout de
liaison permanent alors que l'ESP32 emettait correctement.
Remplace par parse_hex2(), borne a exactement deux chiffres, qui ne
depend d'aucune terminaison et rejette un checksum malforme. Supprime au
passage la dependance a stdlib.
status_led.c/h -- affichage d'etat
STARTUP bleu fixe (1 s minimum, sinon jamais visible)
NOMINAL bleu 0,2 / 1,8 s
LINK_LOST bleu 0,2 / 0,2 s (> 2 s sans trame $C valide)
EMUSTOP alternance bleu/rouge 0,5 / 0,5 s
OVERTEMP rouge 0,5 / 0,5 s
OVERCURRENT rouge fixe
Priorite : surintensite > surtemperature > EMUSTOP > liaison perdue.
La surintensite passe devant EMUSTOP : en developpement EMUSTOP se
declenche en permanence et ne doit jamais masquer un defaut de puissance.
Limite de principe : pendant une halte CPU, plus aucun code ne tourne,
les GPIO restent figes sur la phase courante du motif. L'alternance
EMUSTOP est donc un indicateur a posteriori, jamais un etat live.
safety.c/h -- origine du trip
TZFLG.DCAEVT1 (bit 3) est distinct de TZFLG.OST (bit 2), ce qui permet de
separer une surintensite reelle (comparateur) d'un arret du debugger.
Les ISR ne pilotent plus les LED, elles ne font que relever la cause.
Protection thermique (main.c, calib.h)
Seuil 85 degC avec hysteresis de 10 degC, coupure du PWM et de HV_EN.
Lente par nature, donc entierement logicielle -- aucun chemin materiel
requis, contrairement a la surintensite.
Pas de redemarrage automatique : rien ne reactive le PWM une fois coupe.
Seuil PROVISOIRE : les NTC sont a 5 mm des MOSFET, donc elles mesurent le
cuivre et non la jonction (ecart statique et retard thermique notables).
A recaler quand la temperature de boitier en charge sera connue.
Valide sur cible : commandes $C de nouveau acceptees, chaine NTC lue a
24,5 / 24,7 degC sur pont 10k/10k (coherent avec des resistances a 1 %).
Note : un pont 10k/10k ne discrimine PAS le sens de la formule NTC, les
deux formes coincidant au point d'equilibre. Verification a faire avec une
resistance asymetrique (4,7 kOhm -> environ 47 degC).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Report des mesures de docs/mesure-cartepuissance.md dans calib.h, avec une
structure par voie (gain, offset) plutot que des constantes isolees.
calib.h
Tensions : VIN 11,11 / V1 31,25 / VOUT 181,82 V/V (mesures)
IIN : 1,2019 A/V -- un seul point mesure, offset suppose nul
IOUT : 0,016667 A/V -- NON MESURE, valeur theorique de conception
Shunts : I1 offset 47,3 mV gain 0,631 V/A
I2 offset 34,0 mV gain 0,637 V/A
Deux jeux separes : les voies different d'environ 1 % en gain
et n'ont pas le meme offset, ne jamais moyenner.
Seuil de protection : le code DAC est maintenant calcule par macro a partir
de SAFETY_ISHUNT_THRESHOLD_A et des gain/offset mesures, et il est PROPRE A
CHAQUE ETAGE (601 et 603 au lieu d'un 558 commun).
Correction d'analyse : le 558 precedent supposait un gain de 30 pile. Le
gain reel etant plus eleve (~31,5), le seuil de 1,8 V etait atteint a
2,78 A et non a 3 A -- la protection declenchait donc TROP TOT, et non
trop tard comme indique au §5 du document de mesures. Conservatif, sans
danger, mais corrige.
measure.c/h (etape 5)
measure_vin/iin/v1/vout/iout/i1/i2/temp, signature float f(uint16_t raw).
Deux fonctions distinctes pour les shunts, puisque gain ET offset
different. measure_i1/i2 peuvent renvoyer une valeur negative a courant
nul : volontaire, une derive d'offset apres changement d'ampli devient
ainsi visible en telemetrie au lieu d'etre masquee par une saturation.
NTC : la relation du PROMPT §5 est INVERSEE. Avec la NTC cote 3,3 V c'est
R_ntc = R_fixe * (VREF - Vadc) / Vadc. Verifie sur les points de repere du
PROMPT lui-meme : 0,75 V a 0 degC donne 34,2 kOhm, ce que beta=4000
predit, alors que la forme inversee donnerait 2,94 kOhm (donc du chaud).
Telle qu'ecrite, la protection thermique aurait ete inexploitable.
La telemetrie transporte desormais de vraies grandeurs physiques.
Reste en suspens (voir docs/mesure-cartepuissance.md §6) : IOUT jamais
mesure, second point pour IIN, valeur reelle de la resistance fixe des
ponts NTC, et surtout gain/offset des shunts A REMESURER apres passage du
MCP6001 au TLV9151 -- l'offset actuel est domine par le Vos de l'ampli.
Note : l'"auto-zero logiciel au boot" evoque dans le document de mesures
n'existe pas dans le firmware et n'a pas ete ajoute ; mesurer un offset au
boot figerait une valeur fausse si du courant circule deja.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Campagne de bring-up materiel complete, carte de conversion DECONNECTEE.
pwm.c/h (etape 6) -- valide au scope
ePWM1 -> etage 1, EPWM1A/GPIO0/broche 29, 200 kHz (TBPRD=299)
ePWM2 -> etage 2, EPWM2A/GPIO2/broche 37, 100 kHz (TBPRD=599)
Mode up-count, TBCLK = SYSCLKOUT = 60 MHz, duty 0 au demarrage,
inhibition par forcage continu AQCSFRC. Tranche le point ouvert §9.1.
HRPWM non implemente, notes de portage consignees dans pwm.c.
adc.c/h (etape 4) -- 9 voies validees, T1/T2 comprises
Reference interne (ADCREFSEL=0), SOC declenches par ePWM1 SOCA avec
SOCAPRD=3 (~66 kHz), jamais en free-run. ISR ADCINT1 courte : rangement
des valeurs brutes uniquement, aucun flottant.
Note materielle : les 9 voies lisaient 4095 tant que VDDA (broche 11)
n'etait pas alimentee -- y compris VREFLO converti en interne, ce qui a
permis d'ecarter le logiciel.
bsp_gpio (etape 3)
HV_EN (GPIO32), Stage1/2-EN (GPIO16/17) en sortie, etat sur a 0, et
pull-ups internes de GPIO16/17 desactivees : sinon elles presentent un 1
sur une entree de chaque porte ET avant que le firmware ne tourne.
bsp_gpio_stage_default_override_init() : pilotage manuel de GPIO1/GPIO3
pour valider les portes ET, exclusif avec safety_init().
safety_arm_emustop_only() -- BRING-UP
Arme TZ6 seul, sans les comparateurs, pour valider EMUSTOP isolement
quand les entrees shunt ne sont pas cablees.
Resultats materiels :
- portes ET IC8/IC9 : sortie = ET logique des deux entrees, verifie au
scope avec des cadences distinctes (default 400 ms, EN 1 s)
- comparateur : entree shunt 0 -> 3 V declenche bien le trip
- EMUSTOP : arret du debugger -> broches 29 et 37 a 0, TZFLG.OST latche,
et le flag ne se rearme pas apres continue
- un trip EMUSTOP ne peut PAS etre efface tant que le CPU est halte (la
source reste assertee) : l'effacement devra passer par une commande
UART en fonctionnement (etape 7)
main.c contient encore le bloc de bring-up (PWM force a 50 %, telemetrie
transportant les tensions ADC brutes en volts) : A RETIRER, et remplacer
safety_arm_emustop_only() par safety_init(), avant toute mise sous tension
de la puissance (PROMPT §8).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Emission $T,...*XX et reception $C,...*XX conformes a docs/ESP32-UART.md.
Trame mesuree a 129 caracteres, checksum XOR verifie independamment.
Corrections trouvees au bring-up sur materiel :
- StartCpuTimer0() manquant : ConfigCpuTimer() laisse le timer arrete, donc
le tick d'emission ne se produisait jamais et rien ne partait sur la ligne.
- Suppression de "%f" dans sprintf. Sur C28x le support flottant de printf
passe par du long double 64 bits emule (frexpl/scalbnl/L$$DIV) : le CPU
partait a PC=0 des le premier envoi. Formatage decimal manuel a la place,
comme le prevoyait deja PROMPT §7 etape 7.
- RXFFIENA n'etait pas arme dans SCIFFRX : aucune interruption de reception.
- Recuperation de SCIRXST.RXERROR. Un FE/OE/PE/BRKDT le latche et bloque le
recepteur jusqu'a un SW RESET du SCI ; sans ca une seule perturbation
arretait la reception definitivement (constate : RXERROR+FE+BRKDT latches).
- Formatage borne : clamp des valeurs (NaN et saturation) puis snprintf avec
la capacite restante. Un champ qui ne tient pas est abandonne entierement,
ce que le protocole autorise, plutot que de deborder s_tx_frame.
- Emission non bloquante : send_telemetry() ne fait que mettre en attente,
uart_link_service_tx() pousse au plus une FIFO (4 octets) puis rend la
main. L'ancienne version monopolisait 22 ms par trame, incompatible avec
la priorite donnee a la boucle de regulation.
Plan memoire (F2802x_generic_flash.cmd) :
- les 4 secteurs flash du F28027 sont declares (32K mots au lieu de 8K)
- .ebss bascule en RAML0 : il etait colle juste apres .stack, donc tout
debordement de pile ecrasait silencieusement les globales
- pile portee a 1024 mots, seule dans RAMM1
LED : polarite reelle confirmee active-haut (cathode commune a la masse,
anodes pilotees par GPIO12/GPIO33 a travers 1k) -> LED_ACTIVE_LOW = 0.
Repond au point ouvert §9.2 du PROMPT.
safety_init() reste desactive dans main.c : bring-up isole LED+UART, a
reactiver quand l'etage de puissance sera cable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit replaced the hardcoded path with a variable
reference to itself (${COM_TI_C2000WARE_INSTALL_DIR}), which broke
include resolution and the build entirely. Restore the absolute path
confirmed via getProjectProductReferences.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.mcp.json and CLAUDE.md are auto-generated by CCS with machine-specific
absolute paths and shouldn't be shared via git. The .cproject change
(likely from a CCS reimport) replaces the hardcoded C2000Ware install
path with a variable reference.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>