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>
This commit is contained in:
2026-08-05 21:28:34 +02:00
parent b1bb0fa21a
commit 69801df648
10 changed files with 333 additions and 48 deletions

View File

@ -22,8 +22,8 @@
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> <storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactExtension="out" artifactName="Example_2802xLEDBlink" buildProperties="" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.1909800144" name="Debug" parent="com.ti.ccstudio.buildDefinitions.C2000.Debug"> <configuration artifactExtension="out" artifactName="Example_2802xLEDBlink" buildProperties="" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.1909800144" name="Debug" parent="com.ti.ccstudio.buildDefinitions.C2000.Debug">
<folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Debug.1909800144.847706334" name="/" resourcePath=""> <folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Debug.1909800144.847706334" name="/" resourcePath="">
<toolChain id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.DebugToolchain.159661892" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.DebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug.1551753352"> <toolChain id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.DebugToolchain.213001512" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.DebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug.813574046">
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1144356066" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList"> <option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1793914701" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
<listOptionValue value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28027"/> <listOptionValue value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28027"/>
<listOptionValue value="DEVICE_CORE_ID="/> <listOptionValue value="DEVICE_CORE_ID="/>
<listOptionValue value="DEVICE_ENDIANNESS=UNKNOWN"/> <listOptionValue value="DEVICE_ENDIANNESS=UNKNOWN"/>
@ -38,14 +38,14 @@
<listOptionValue value="LINK_ORDER="/> <listOptionValue value="LINK_ORDER="/>
<listOptionValue value="PRODUCTS=C2000WARE:26.1.0.00;"/> <listOptionValue value="PRODUCTS=C2000WARE:26.1.0.00;"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1164917113" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="25.11.1.LTS" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.841378290" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="25.11.1.LTS" valueType="string"/>
<targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.targetPlatformDebug.304590691" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.targetPlatformDebug"/> <targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.targetPlatformDebug.524055294" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.targetPlatformDebug"/>
<builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.builderDebug.1772446421" name="GNU Make.Debug" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.builderDebug"/> <builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.builderDebug.1769976716" name="GNU Make.Debug" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.builderDebug"/>
<tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.compilerDebug.1541428198" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.compilerDebug"> <tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.compilerDebug.305010793" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.compilerDebug">
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.LARGE_MEMORY_MODEL.1715790107" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.LARGE_MEMORY_MODEL.1798142386" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.UNIFIED_MEMORY.1984521868" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.UNIFIED_MEMORY.1604870518" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION.2036393650" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION.28" valueType="enumerated"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION.2122353486" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.SILICON_VERSION.28" valueType="enumerated"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.INCLUDE_PATH.1849469441" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.INCLUDE_PATH" valueType="includePath"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.INCLUDE_PATH.716974798" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.INCLUDE_PATH" valueType="includePath">
<listOptionValue value="${COM_TI_C2000WARE_INCLUDE_PATH}"/> <listOptionValue value="${COM_TI_C2000WARE_INCLUDE_PATH}"/>
<listOptionValue value="${CG_TOOL_ROOT}/include"/> <listOptionValue value="${CG_TOOL_ROOT}/include"/>
<listOptionValue value="${INSTALLROOT_F2802x}/headers/include"/> <listOptionValue value="${INSTALLROOT_F2802x}/headers/include"/>
@ -53,35 +53,36 @@
<listOptionValue value="${INSTALLROOT_F2802x}/common/include"/> <listOptionValue value="${INSTALLROOT_F2802x}/common/include"/>
<listOptionValue value="${INSTALLROOT_IQMATH}/include"/> <listOptionValue value="${INSTALLROOT_IQMATH}/include"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEFINE.1614629519" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEFINE" valueType="definedSymbols"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEFINE.1404568356" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEFINE" valueType="definedSymbols">
<listOptionValue value="${COM_TI_C2000WARE_SYMBOLS}"/> <listOptionValue value="${COM_TI_C2000WARE_SYMBOLS}"/>
<listOptionValue value="_DEBUG"/> <listOptionValue value="_DEBUG"/>
<listOptionValue value="LARGE_MODEL"/> <listOptionValue value="LARGE_MODEL"/>
<listOptionValue value="_FLASH"/> <listOptionValue value="_FLASH"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL.196664150" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL.1187109720" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_SUPPRESS.689463295" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_SUPPRESS" valueType="stringList"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_SUPPRESS.288154142" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_SUPPRESS" valueType="stringList">
<listOptionValue value="232"/> <listOptionValue value="232"/>
<listOptionValue value="10063"/> <listOptionValue value="10063"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_WARNING.1851392201" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_WARNING" valueType="stringList"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_WARNING.923695198" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.DIAG_WARNING" valueType="stringList">
<listOptionValue value="225"/> <listOptionValue value="225"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ISSUE_REMARKS.19643992" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ISSUE_REMARKS" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ISSUE_REMARKS.1620598451" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ISSUE_REMARKS" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.VERBOSE_DIAGNOSTICS.1636041796" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.VERBOSE_DIAGNOSTICS" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.VERBOSE_DIAGNOSTICS.537099600" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.VERBOSE_DIAGNOSTICS" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL.255072012" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL.QUIET" valueType="enumerated"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL.946759491" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.QUIET_LEVEL.QUIET" valueType="enumerated"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI.1040365072" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI.coffabi" valueType="enumerated"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI.1717529760" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.ABI.coffabi" valueType="enumerated"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.OPT_LEVEL.813239093" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_25.11.compilerID.OPT_LEVEL.2" valueType="enumerated"/>
</tool> </tool>
<tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug.1551753352" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug"> <tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug.813574046" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.exe.linkerDebug">
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.STACK_SIZE.164177814" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.STACK_SIZE" value="0x400" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.STACK_SIZE.1069850252" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.STACK_SIZE" value="0x400" valueType="string"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.MAP_FILE.1243476423" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.MAP_FILE" value="&quot;Example_2802xLEDBlink.map&quot;" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.MAP_FILE.775342445" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.MAP_FILE" value="&quot;Example_2802xLEDBlink.map&quot;" valueType="string"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.OUTPUT_FILE.119763382" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.OUTPUT_FILE" value="Example_2802xLEDBlink.out" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.OUTPUT_FILE.1826875140" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.OUTPUT_FILE" value="Example_2802xLEDBlink.out" valueType="string"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.LIBRARY.397023344" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.LIBRARY" valueType="libs"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.LIBRARY.1024492364" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.LIBRARY" valueType="libs">
<listOptionValue value="${COM_TI_C2000WARE_LIBRARIES}"/> <listOptionValue value="${COM_TI_C2000WARE_LIBRARIES}"/>
<listOptionValue value="rts2800_ml.lib"/> <listOptionValue value="rts2800_ml.lib"/>
<listOptionValue value="IQmath.lib"/> <listOptionValue value="IQmath.lib"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.SEARCH_PATH.567141830" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.SEARCH_PATH" valueType="libPaths"> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.SEARCH_PATH.1469209174" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.SEARCH_PATH" valueType="libPaths">
<listOptionValue value="${COM_TI_C2000WARE_LIBRARY_PATH}"/> <listOptionValue value="${COM_TI_C2000WARE_LIBRARY_PATH}"/>
<listOptionValue value="${CG_TOOL_ROOT}/lib"/> <listOptionValue value="${CG_TOOL_ROOT}/lib"/>
<listOptionValue value="${CG_TOOL_ROOT}/include"/> <listOptionValue value="${CG_TOOL_ROOT}/include"/>
@ -89,12 +90,12 @@
<listOptionValue value="${INSTALLROOT_F2802x}/common/lib"/> <listOptionValue value="${INSTALLROOT_F2802x}/common/lib"/>
<listOptionValue value="${INSTALLROOT_IQMATH}/lib"/> <listOptionValue value="${INSTALLROOT_IQMATH}/lib"/>
</option> </option>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ISSUE_REMARKS.1756602824" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ISSUE_REMARKS" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ISSUE_REMARKS.1110979405" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ISSUE_REMARKS" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.VERBOSE_DIAGNOSTICS.489766963" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.VERBOSE_DIAGNOSTICS" value="true" valueType="boolean"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.VERBOSE_DIAGNOSTICS.113431991" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.VERBOSE_DIAGNOSTICS" value="true" valueType="boolean"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.XML_LINK_INFO.667790640" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.XML_LINK_INFO" value="&quot;Example_2802xLEDBlink_linkInfo.xml&quot;" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.XML_LINK_INFO.460865356" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.XML_LINK_INFO" value="&quot;Example_2802xLEDBlink_linkInfo.xml&quot;" valueType="string"/>
<option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ENTRY_POINT.511960855" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ENTRY_POINT" value="code_start" valueType="string"/> <option id="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ENTRY_POINT.1851948553" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.linkerID.ENTRY_POINT" value="code_start" valueType="string"/>
</tool> </tool>
<tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.hex.813831478" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.hex"/> <tool id="com.ti.ccstudio.buildDefinitions.C2000_25.11.hex.166197469" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_25.11.hex"/>
</toolChain> </toolChain>
</folderInfo> </folderInfo>
<sourceEntries> <sourceEntries>

View File

@ -1,5 +1,6 @@
#include "DSP28x_Project.h" #include "DSP28x_Project.h"
#include "adc.h" #include "adc.h"
#include "control.h"
#include "calib.h" #include "calib.h"
// Valeurs du champ CHSEL (TRM SPRUI09A) : groupe A = 0x0..0x7, // Valeurs du champ CHSEL (TRM SPRUI09A) : groupe A = 0x0..0x7,
@ -19,6 +20,13 @@ static const uint16_t k_chsel[ADC_CH_COUNT] = {
static volatile uint16_t s_raw[ADC_CH_COUNT]; static volatile uint16_t s_raw[ADC_CH_COUNT];
static volatile uint32_t s_seq_count = 0; static volatile uint32_t s_seq_count = 0;
// Note de mesure (instrumentation retiree) : la duree de cette ISR a ete
// mesuree au scope en basculant une broche a l'entree et a la sortie.
// Resultat apres correction des etats d'attente de la flash : 4,9 us pour
// une periode de 15 us, soit 33 % de charge CPU a 66,85 kHz.
// Ne PAS refaire cette mesure sur GPIO32 : c'est HV_EN, la commande de
// l'optocoupleur VOM1271. Utiliser une broche libre (GPIO4, 6 ou 7).
interrupt void adc_int1_isr(void); interrupt void adc_int1_isr(void);
void adc_init(void) void adc_init(void)
@ -136,6 +144,11 @@ interrupt void adc_int1_isr(void)
s_seq_count++; s_seq_count++;
// Point d'appel cadence de la commande (PROMPT §6 etape 8 : dt constant,
// dans l'ISR ADC ou PWM). Une sequence ADC complete = une decision.
// Doit rester tres court : ni flottant, ni division, ni attente.
control_tick();
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
} }

View File

@ -9,4 +9,20 @@ void bsp_clock_init(void)
EDIS; EDIS;
InitSysCtrl(); InitSysCtrl();
#ifdef _FLASH
// Etats d'attente de la flash. Au reset ils valent leur MAXIMUM
// (FBANKWAIT = 0x0F0F, soit RANDWAIT = PAGEWAIT = 15) : chaque acces
// coute alors 16 cycles au lieu des 3 necessaires a 60 MHz, et TOUT le
// code resident en flash tourne environ 4 fois trop lentement.
//
// Mesure avant/apres sur l'ISR ADC : c'etait le facteur dominant, bien
// devant l'optimisation du compilateur.
//
// InitFlash() DOIT s'executer depuis la RAM (elle reconfigure la flash
// sous ses propres pieds) : c'est tout l'objet du memcpy des ramfuncs
// fait en tete de main(), qui existait deja mais ne servait a rien
// puisque la fonction n'etait jamais appelee.
InitFlash();
#endif
} }

View File

@ -117,6 +117,13 @@
// valeur, rouge sinon. 300 mV = 372 LSB en pleine echelle 3,3 V. // valeur, rouge sinon. 300 mV = 372 LSB en pleine echelle 3,3 V.
#define ADC_TEST_THRESHOLD_V 0.3f #define ADC_TEST_THRESHOLD_V 0.3f
// ---- Balayage de caracterisation (BRING-UP, boucle ouverte) ---------
// Rampe montante puis descendante entre ces deux bornes, par pas de 1 LSB
// de CMPA a chaque conversion ADC. Sert a mesurer la vitesse de correction
// atteignable, pas a reguler. A supprimer avec le reste du harnais.
#define CONTROL_SWEEP_MIN_PCT 1.0f
#define CONTROL_SWEEP_MAX_PCT 50.0f
// Frequences de decoupage par etage (point ouvert §9.1 du PROMPT, tranche au // Frequences de decoupage par etage (point ouvert §9.1 du PROMPT, tranche au
// bring-up). TBCLK = SYSCLKOUT = 60 MHz, TBPRD = SYSCLKOUT/Fpwm - 1 : // bring-up). TBCLK = SYSCLKOUT = 60 MHz, TBPRD = SYSCLKOUT/Fpwm - 1 :
// etage 1 : 200 kHz -> TBPRD = 299 // etage 1 : 200 kHz -> TBPRD = 299

121
src/control.c Normal file
View File

@ -0,0 +1,121 @@
#include "control.h"
#include "pwm.h"
#include "bsp_gpio.h"
#include "calib.h"
// Bornes du balayage, en counts, calculees une fois a l'init depuis la
// periode reelle de chaque etage. Elles different d'un etage a l'autre :
// 300 counts a 200 kHz contre 600 a 100 kHz.
static uint16_t s_min_counts[2];
static uint16_t s_max_counts[2];
static uint16_t s_counts[2];
static bool s_rising[2];
static volatile bool s_armed = false;
// Compteur d'allers-retours complets, lisible au debogueur : permet de
// verifier que le balayage tourne sans avoir a sonder les broches.
static volatile uint32_t s_sweep_cycles = 0;
static uint16_t pct_to_counts(uint16_t period, float pct)
{
uint16_t c = (uint16_t)((pct / 100.0f) * (float)period + 0.5f);
// Au moins 1 LSB : un duty de 0 ne serait pas un balayage mais un arret.
if (c == 0U)
{
c = 1U;
}
if (c > period)
{
c = period;
}
return c;
}
void control_init(void)
{
uint16_t i;
stage_id_t stages[2] = {STAGE_1, STAGE_2};
for (i = 0U; i < 2U; i++)
{
uint16_t period = pwm_get_period_counts(stages[i]);
s_min_counts[i] = pct_to_counts(period, CONTROL_SWEEP_MIN_PCT);
s_max_counts[i] = pct_to_counts(period, CONTROL_SWEEP_MAX_PCT);
s_counts[i] = s_min_counts[i];
s_rising[i] = true;
}
s_armed = false;
s_sweep_cycles = 0;
}
void control_start(void)
{
uint16_t i;
stage_id_t stages[2] = {STAGE_1, STAGE_2};
// Les deux etages repartent ensemble du minimum.
for (i = 0U; i < 2U; i++)
{
s_counts[i] = s_min_counts[i];
s_rising[i] = true;
pwm_set_duty_counts(stages[i], s_counts[i]);
}
s_armed = true;
}
void control_stop(void)
{
s_armed = false;
}
// Appelee en ISR : que des comparaisons, incrementations et decrementations.
// Le tableau des identifiants est en static const, pas en local : une
// initialisation locale serait recopiee sur la pile a chaque appel, soit
// plusieurs milliers de fois par seconde pour rien.
static const stage_id_t k_stages[2] = {STAGE_1, STAGE_2};
void control_tick(void)
{
uint16_t i;
if (!s_armed)
{
return;
}
for (i = 0U; i < 2U; i++)
{
if (s_rising[i])
{
if (s_counts[i] < s_max_counts[i])
{
s_counts[i]++;
}
else
{
s_rising[i] = false;
}
}
else
{
if (s_counts[i] > s_min_counts[i])
{
s_counts[i]--;
}
else
{
s_rising[i] = true;
if (i == 0U)
{
s_sweep_cycles++; // compte les allers-retours de l'etage 1
}
}
}
pwm_set_duty_counts(k_stages[i], s_counts[i]);
}
}

32
src/control.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef CONTROL_H
#define CONTROL_H
#include <stdbool.h>
#include <stdint.h>
// Emplacement de la future regulation (PROMPT §6 etape 8). Pour l'instant
// ce module ne contient PAS de regulation : il execute un balayage de duty
// en boucle OUVERTE, destine a caracteriser la vitesse de correction
// atteignable. Aucune mesure n'influence encore le duty.
//
// Le balayage va de CONTROL_SWEEP_MIN_PCT a CONTROL_SWEEP_MAX_PCT puis
// revient, par pas de 1 LSB de CMPA a chaque conversion ADC -- c'est-a-dire
// le plus petit increment realisable, et la cadence la plus rapide dont on
// dispose sans ajouter d'interruption.
void control_init(void);
// Arme le balayage et repositionne les deux etages au duty minimal.
void control_start(void);
// Fige le balayage. Le duty n'est pas modifie : c'est pwm_enable() et le
// Trip Zone qui coupent reellement les sorties.
void control_stop(void);
// A appeler a CADENCE FIXE depuis l'ISR ADC (PROMPT §6 etape 8 : "prevoir
// l'emplacement d'appel cadence, dt constant"). Ne fait rien si le balayage
// n'est pas arme. Sans flottant ni division : un increment et une ecriture
// de registre par etage.
void control_tick(void);
#endif

View File

@ -8,6 +8,7 @@
#include "adc.h" #include "adc.h"
#include "measure.h" #include "measure.h"
#include "status_led.h" #include "status_led.h"
#include "control.h"
#include "calib.h" #include "calib.h"
extern uint16_t RamfuncsLoadStart; extern uint16_t RamfuncsLoadStart;
@ -71,13 +72,9 @@ static void start_conversion(void)
stage_enable_set(STAGE_1, true); stage_enable_set(STAGE_1, true);
stage_enable_set(STAGE_2, true); stage_enable_set(STAGE_2, true);
// ---- BRING-UP : duty applique d'un coup, SANS rampe de soft-start. -- // Le duty est desormais pilote par control.c, qui repart du minimum.
// A REMPLACER par la rampe avant toute mise sous tension de la // Les deux etages demarrent ensemble.
// puissance, et a supprimer entierement quand control.c pilotera le control_start();
// duty (etape 8).
pwm_set_duty(STAGE_1, 0.5f);
pwm_set_duty(STAGE_2, 0.5f);
// ---------------------------------------------------------------------
} }
// Priorite 2 > 3 > 4 > 5 > 1 : EMUSTOP est le code le moins prioritaire // Priorite 2 > 3 > 4 > 5 > 1 : EMUSTOP est le code le moins prioritaire
@ -115,6 +112,7 @@ static fault_code_t compute_fault_code(const safety_faults_t *f)
// reellement la charge (PROMPT §6 etape 6). // reellement la charge (PROMPT §6 etape 6).
static void enter_safe_state(void) static void enter_safe_state(void)
{ {
control_stop();
pwm_enable(STAGE_1, false); pwm_enable(STAGE_1, false);
pwm_enable(STAGE_2, false); pwm_enable(STAGE_2, false);
stage_enable_set(STAGE_1, false); stage_enable_set(STAGE_1, false);
@ -187,6 +185,10 @@ void main(void)
// comparateur ne declenchera donc pas spontanement. // comparateur ne declenchera donc pas spontanement.
safety_init(); safety_init();
// control_init() lit les periodes ePWM, donc apres pwm_init(), et avant
// adc_init() dont l'ISR appellera control_tick().
control_init();
// ADC : declenche par ePWM1, donc apres pwm_init(). // ADC : declenche par ePWM1, donc apres pwm_init().
adc_init(); adc_init();
uart_link_init(); uart_link_init();
@ -273,8 +275,11 @@ void main(void)
// ci-dessus, pas encore une mesure. // ci-dessus, pas encore une mesure.
t.freq1_hz = (float)PWM_STAGE1_FREQ_HZ; t.freq1_hz = (float)PWM_STAGE1_FREQ_HZ;
t.freq2_hz = (float)PWM_STAGE2_FREQ_HZ; t.freq2_hz = (float)PWM_STAGE2_FREQ_HZ;
t.duty1_pct = 50.0f; // Duty reellement en sortie, relu depuis CMPA. Pendant le
t.duty2_pct = 50.0f; // balayage la valeur change bien plus vite que la cadence de
// telemetrie : c'est un echantillon, pas un suivi.
t.duty1_pct = pwm_get_duty(STAGE_1) * 100.0f;
t.duty2_pct = pwm_get_duty(STAGE_2) * 100.0f;
t.vin_v = measure_vin(adc_get_raw(ADC_CH_VIN)); t.vin_v = measure_vin(adc_get_raw(ADC_CH_VIN));
t.iin_a = measure_iin(adc_get_raw(ADC_CH_IIN)); t.iin_a = measure_iin(adc_get_raw(ADC_CH_IIN));
t.v1_v = measure_v1(adc_get_raw(ADC_CH_V1)); t.v1_v = measure_v1(adc_get_raw(ADC_CH_V1));
@ -303,12 +308,16 @@ void main(void)
// //
// Les LED n'affichent plus l'etat de l'ADC mais celui des defauts, pilotees // Les LED n'affichent plus l'etat de l'ADC mais celui des defauts, pilotees
// depuis la boucle principale. // depuis la boucle principale.
// Aucune multiplication ni division ici : le rythme de la telemetrie est
// obtenu par un compteur qui reboucle sur comparaison, pas par un modulo
// (division logicielle sur C28x).
#define TELEMETRY_PERIOD_TICKS 30U // 300 ms
interrupt void cpu_timer0_isr(void) interrupt void cpu_timer0_isr(void)
{ {
static uint16_t tick = 0; static uint16_t telemetry_tick = 0;
CpuTimer0.InterruptCount++; CpuTimer0.InterruptCount++;
tick++;
status_led_tick(); status_led_tick();
@ -317,9 +326,11 @@ interrupt void cpu_timer0_isr(void)
s_ticks_since_cmd++; // sature au seuil, pas de rebouclage s_ticks_since_cmd++; // sature au seuil, pas de rebouclage
} }
if ((tick % 30U) == 0U) telemetry_tick++;
if (telemetry_tick >= TELEMETRY_PERIOD_TICKS)
{ {
s_send_telemetry = true; // telemetrie toutes les 300 ms telemetry_tick = 0U;
s_send_telemetry = true;
} }
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

View File

@ -138,6 +138,42 @@ void pwm_set_duty(stage_id_t stage, float duty_0_1)
pwm_apply_duty(stage); pwm_apply_duty(stage);
} }
float pwm_get_duty(stage_id_t stage)
{
volatile struct EPWM_REGS *p = pwm_regs(stage);
uint16_t period = (uint16_t)(p->TBPRD + 1U);
if (period == 0U)
{
return 0.0f;
}
return (float)p->CMPA.half.CMPA / (float)period;
}
uint16_t pwm_get_period_counts(stage_id_t stage)
{
return (uint16_t)(pwm_regs(stage)->TBPRD + 1U);
}
void pwm_set_duty_counts(stage_id_t stage, uint16_t counts)
{
volatile struct EPWM_REGS *p = pwm_regs(stage);
uint16_t period = (uint16_t)(p->TBPRD + 1U);
if (counts > period)
{
counts = period;
}
p->CMPA.half.CMPA = counts;
// PAS de mise a jour de la consigne flottante ici : cette fonction est
// appelee depuis l'ISR ADC a plusieurs dizaines de kHz, et le F28027
// n'a pas d'unite flottante -- une division y coutait plusieurs
// centaines de cycles et effondrait la cadence de l'ISR.
// pwm_get_duty() relit CMPA, la telemetrie reste donc juste.
}
void pwm_enable(stage_id_t stage, bool enabled) void pwm_enable(stage_id_t stage, bool enabled)
{ {
volatile struct EPWM_REGS *p = pwm_regs(stage); volatile struct EPWM_REGS *p = pwm_regs(stage);

View File

@ -20,6 +20,18 @@ void pwm_set_freq(stage_id_t stage, uint32_t hz);
// duty exprime en 0..1. Sature hors bornes. // duty exprime en 0..1. Sature hors bornes.
void pwm_set_duty(stage_id_t stage, float duty_0_1); void pwm_set_duty(stage_id_t stage, float duty_0_1);
// Duty courant (0..1), reconstruit depuis CMPA : reflete donc ce qui sort
// reellement, y compris apres un reglage en counts.
float pwm_get_duty(stage_id_t stage);
// ---- Reglage en pas de compteur --------------------------------------
// Le pas minimal realisable est 1 LSB de CMPA, et il DEPEND DE L'ETAGE :
// 1/300 = 0,333 % a 200 kHz, 1/600 = 0,167 % a 100 kHz. Une consigne en
// flottant ne permet pas d'exprimer "le plus petit pas possible" ; ces
// deux fonctions si.
uint16_t pwm_get_period_counts(stage_id_t stage); // TBPRD + 1
void pwm_set_duty_counts(stage_id_t stage, uint16_t counts);
// Inhibition logicielle par forcage continu de la sortie a l'etat bas // Inhibition logicielle par forcage continu de la sortie a l'etat bas
// (AQCSFRC). N'a rien a voir avec la protection materielle : le Trip Zone // (AQCSFRC). N'a rien a voir avec la protection materielle : le Trip Zone
// reste le seul mecanisme de securite (PROMPT §8). // reste le seul mecanisme de securite (PROMPT §8).

View File

@ -50,8 +50,14 @@ void status_led_set_state(led_state_t state)
} }
} }
// Appelee en ISR : aucune multiplication ni division. Le compteur de phase
// reboucle par COMPARAISON, jamais par modulo -- sur C28x un "%" par une
// valeur qui n'est pas une puissance de deux est une division logicielle,
// donc plusieurs dizaines de cycles.
void status_led_tick(void) void status_led_tick(void)
{ {
uint16_t period;
uint16_t on_time;
bool blue = false; bool blue = false;
bool red = false; bool red = false;
@ -60,25 +66,55 @@ void status_led_tick(void)
s_startup_hold--; s_startup_hold--;
} }
// Periode et duree du niveau actif du motif courant.
switch (s_state)
{
case LED_STATE_NOMINAL:
period = NOMINAL_PERIOD;
on_time = NOMINAL_ON;
break;
case LED_STATE_LINK_LOST:
period = LINK_LOST_PERIOD;
on_time = LINK_LOST_ON;
break;
case LED_STATE_EMUSTOP:
period = EMUSTOP_PERIOD;
on_time = EMUSTOP_HALF;
break;
case LED_STATE_OVERTEMP:
period = OVERTEMP_PERIOD;
on_time = OVERTEMP_ON;
break;
default: // STARTUP et OVERCURRENT : niveau fixe, pas de motif
period = 1U;
on_time = 1U;
break;
}
s_phase++; s_phase++;
if (s_phase >= period)
{
s_phase = 0U;
}
switch (s_state) switch (s_state)
{ {
case LED_STATE_NOMINAL: case LED_STATE_NOMINAL:
blue = ((s_phase % NOMINAL_PERIOD) < NOMINAL_ON);
break;
case LED_STATE_LINK_LOST: case LED_STATE_LINK_LOST:
blue = ((s_phase % LINK_LOST_PERIOD) < LINK_LOST_ON); blue = (s_phase < on_time);
break; break;
case LED_STATE_EMUSTOP: case LED_STATE_EMUSTOP:
blue = ((s_phase % EMUSTOP_PERIOD) < EMUSTOP_HALF); blue = (s_phase < on_time);
red = !blue; red = !blue;
break; break;
case LED_STATE_OVERTEMP: case LED_STATE_OVERTEMP:
red = ((s_phase % OVERTEMP_PERIOD) < OVERTEMP_ON); red = (s_phase < on_time);
break; break;
case LED_STATE_OVERCURRENT: case LED_STATE_OVERCURRENT: