2 Commits

Author SHA1 Message Date
69801df648 InitFlash manquante : tout le firmware tournait 4x trop lentement
DEFAUT PRINCIPAL -- etats d'attente de la flash jamais configures

  Le firmware s'execute depuis la flash (_FLASH), mais InitFlash() n'etait
  jamais appelee. Au reset FBANKWAIT vaut son MAXIMUM (0x0F0F, soit
  RANDWAIT = PAGEWAIT = 15) : chaque acces flash coutait 16 cycles au lieu
  des 3 necessaires a 60 MHz.

  Ironie : le memcpy des ramfuncs en tete de main() existe PRECISEMENT pour
  copier InitFlash() en RAM, puisqu'elle doit s'executer hors flash. La
  recopie se faisait depuis le premier jour sans que la fonction ne soit
  jamais appelee -- la section ramfuncs ne contenait que 4 mots, elle en
  fait 0x21 maintenant.

  Mesure au scope sur l'ISR ADC :
    avant : 22,3 kHz, ISR 30 us, 88 % de charge CPU
    apres : 66,85 kHz, ISR 4,9 us, 33 % de charge CPU
  66,85 kHz est le maximum theorique (200 kHz / SOCAPRD=3), atteint sans
  aucun declenchement manque. Recoupe au compteur : 67,5 kHz.

Optimisation compilateur

  -O2 ajoute : le projet compilait sans aucune option d'optimisation.
  Contribution mesuree : ISR de 41 a 30 us, mais SANS changer la cadence --
  ce n'etait pas le facteur limitant. Conserve, le gain reste reel.

Discipline ISR (ni multiplication ni division en interruption)

  status_led_tick() : quatre modulos (%200, %40, %100, %100) remplaces par
    un compteur qui reboucle sur comparaison.
  cpu_timer0_isr()  : "tick % 30" remplace par un compteur dedie.
  control_tick()    : le tableau stages[2] etait initialise sur la pile a
    chaque appel, des dizaines de milliers de fois par seconde -> static const.
  pwm_set_duty_counts() : une division flottante y mettait a jour la
    consigne, sur un F28027 sans FPU. Supprimee ; pwm_get_duty() relit
    CMPA, la telemetrie reste juste.

control.c/h -- balayage de caracterisation (BOUCLE OUVERTE)

  Ce module ne regule rien : il balaie le duty de 1 % a 50 % puis revient,
  par pas de 1 LSB de CMPA a chaque conversion ADC. Appel cadence depuis
  l'ISR ADC, conformement a PROMPT §6 etape 8.

  API en counts ajoutee a pwm.c : le pas minimal est 1 LSB de CMPA et
  DEPEND DE L'ETAGE (1/300 = 0,333 % a 200 kHz, 1/600 = 0,167 % a 100 kHz).
  Une consigne flottante ne permet pas d'exprimer "le plus petit pas".

  Resultat mesure a 66,7 kHz :
    etage 1 : 1->50 % en 2,2 ms, cycle 4,4 ms, 22 %/ms
    etage 2 : 1->50 % en 4,4 ms, cycle 8,9 ms, 11 %/ms
  L'etage 2 est deux fois plus lent PARCE QUE sa resolution est deux fois
  plus fine, a cadence de mise a jour identique.

  La telemetrie transporte desormais le duty reel, relu depuis CMPA.

L'instrumentation de mesure a ete RETIREE : GPIO32 est rendue a HV_EN, qui
en a de nouveau l'usage exclusif (verifie sur cible, broche stable a 0).

Note : ce defaut de wait states etait present depuis le debut du projet.
Toutes les mesures de timing anterieures etaient faussees d'un facteur 4.
Les frequences PWM et les protections sont materielles et restent valides.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 21:28:34 +02:00
a05c1e8124 Machine d'etats LED, protection thermique, et correctif checksum RX
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>
2026-08-03 19:53:32 +02:00