Compare commits
3 Commits
46ddf30a64
...
bringup
| Author | SHA1 | Date | |
|---|---|---|---|
| 69801df648 | |||
| b1bb0fa21a | |||
| 26c1d499e0 |
59
.cproject
59
.cproject
@ -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=""Example_2802xLEDBlink.map"" 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=""Example_2802xLEDBlink.map"" 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=""Example_2802xLEDBlink_linkInfo.xml"" 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=""Example_2802xLEDBlink_linkInfo.xml"" 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>
|
||||||
|
|||||||
@ -5,65 +5,162 @@ pour dialoguer avec l'ESP32-C3 (cote ESP32 deja fonctionnel, voir
|
|||||||
`src/tms_link.cpp` / `include/protocol.h`). Le TMS320 envoie sa telemetrie
|
`src/tms_link.cpp` / `include/protocol.h`). Le TMS320 envoie sa telemetrie
|
||||||
periodiquement, et recoit periodiquement les commandes de l'operateur.
|
periodiquement, et recoit periodiquement les commandes de l'operateur.
|
||||||
|
|
||||||
|
> **Mise a jour** : coefficients de calibration remplaces par les valeurs
|
||||||
|
> mesurees sur la carte reelle (voir `mesure-cartepuissance.md`), et ajout
|
||||||
|
> du champ `FAULT`.
|
||||||
|
|
||||||
## Cablage
|
## Cablage
|
||||||
|
|
||||||
| Signal | ESP32-C3 (config.h) | TMS320 |
|
| Signal | ESP32-C3 (config.h) | TMS320 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| ESP32 TX -> TMS320 RX | GPIO7 | RX |
|
| ESP32 TX -> TMS320 RX | GPIO7 | GPIO28, broche 48 |
|
||||||
| ESP32 RX <- TMS320 TX | GPIO6 | TX |
|
| ESP32 RX <- TMS320 TX | GPIO6 | GPIO29, broche 1 |
|
||||||
| GND commun | GND | GND |
|
| GND commun | GND | GND |
|
||||||
|
|
||||||
A verifier avant de cabler : le TMS320 doit etre en logique 3,3V (comme
|
Niveaux logiques 3,3 V des deux cotes -- **verifie, carte CPU validee**.
|
||||||
l'ESP32-C3). Si sa liaison serie sort en 5V, prevoir un level shifter
|
|
||||||
avant de relier les deux cartes.
|
|
||||||
|
|
||||||
## Parametres UART
|
## Parametres UART
|
||||||
|
|
||||||
- Vitesse : **57600 bauds** (adapte cote TMS320 pour la marge de derive de
|
- Vitesse : **57600 bauds**
|
||||||
l'oscillateur interne INTOSC1 ; l'ESP32 doit etre mis a jour en
|
|
||||||
consequence, `Serial1.begin(57600, ...)`)
|
|
||||||
- Format : **8N1** (8 bits de donnees, pas de parite, 1 bit de stop)
|
- Format : **8N1** (8 bits de donnees, pas de parite, 1 bit de stop)
|
||||||
- Cote ESP32 : `Serial1`, defini dans `TmsLink::begin()`
|
- Cote ESP32 : `Serial1`, defini dans `TmsLink::begin()`
|
||||||
(`src/tms_link.cpp`)
|
|
||||||
|
|
||||||
## Format des trames
|
## Format des trames
|
||||||
|
|
||||||
Protocole ASCII texte, inspire du format NMEA, terminé par `\n` (LF).
|
Protocole ASCII texte, inspire du format NMEA, termine par `\n` (LF).
|
||||||
Chaque trame est encadree par `$` ... `*XX`, ou `XX` est un checksum XOR
|
Chaque trame est encadree par `$` ... `*XX`, ou `XX` est un checksum XOR
|
||||||
en hexadecimal (2 chiffres, majuscules).
|
en hexadecimal (2 chiffres, majuscules).
|
||||||
|
|
||||||
### Telemetrie : TMS320 -> ESP32 (periodique)
|
### Telemetrie : TMS320 -> ESP32 (periodique)
|
||||||
|
|
||||||
```
|
```
|
||||||
$T,FREQ1=100000,FREQ2=100000,DUTY1=45.2,DUTY2=50.0,VIN=400.5,IIN=1.20,V1=200.3,I1=2.50,T1=45.2,VOUT=200.1,I2=2.48,T2=44.8,IOUT=1.05*7A
|
$T,FREQ1=200000,FREQ2=100000,DUTY1=45.2,DUTY2=50.0,VIN=400.5,IIN=1.20,V1=200.3,I1=2.50,T1=45.2,VOUT=200.1,I2=2.48,T2=44.8,IOUT=1.05,FAULT=0*XX
|
||||||
```
|
```
|
||||||
|
|
||||||
Champs (`TAG=valeur`, separes par des virgules, ordre libre) :
|
Champs (`TAG=valeur`, separes par des virgules, ordre libre) :
|
||||||
|
|
||||||
| Tag | Unite | Description |
|
| Tag | Unite | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `FREQ1` | Hz | Frequence de decoupage etage 1 |
|
| `FREQ1` | Hz | Frequence de decoupage etage 1 (200 kHz) |
|
||||||
| `FREQ2` | Hz | Frequence de decoupage etage 2 |
|
| `FREQ2` | Hz | Frequence de decoupage etage 2 (100 kHz) |
|
||||||
| `DUTY1` | % | Rapport cyclique etage 1 |
|
| `DUTY1` | % | Rapport cyclique etage 1 |
|
||||||
| `DUTY2` | % | Rapport cyclique etage 2 |
|
| `DUTY2` | % | Rapport cyclique etage 2 |
|
||||||
| `VIN` | V | Tension d'entree |
|
| `VIN` | V | Tension d'entree |
|
||||||
| `IIN` | A | Courant d'entree |
|
| `IIN` | A | Courant d'entree |
|
||||||
| `V1` | V | Tension etage 1 |
|
| `V1` | V | Tension intermediaire (sortie etage 1) |
|
||||||
| `I1` | A | Courant shunt MOSFET etage 1 |
|
| `I1` | A | Courant shunt MOSFET etage 1 |
|
||||||
| `T1` | °C | Temperature NTC etage 1 |
|
| `T1` | degC | Temperature NTC etage 1 |
|
||||||
| `VOUT` | V | Tension de sortie (sortie boost, etage 2) |
|
| `VOUT` | V | Tension de sortie HT |
|
||||||
| `I2` | A | Courant shunt MOSFET etage 2 |
|
| `I2` | A | Courant shunt MOSFET etage 2 |
|
||||||
| `T2` | °C | Temperature NTC etage 2 |
|
| `T2` | degC | Temperature NTC etage 2 |
|
||||||
| `IOUT` | A | Courant de sortie |
|
| `IOUT` | A | Courant de sortie |
|
||||||
|
| `FAULT` | code 0-5 | Defaut courant (voir ci-dessous) |
|
||||||
|
|
||||||
**Frequence d'envoi recommandee : toutes les 200-500 ms.** L'ESP32
|
### Codes `FAULT`
|
||||||
considere la liaison perdue (`TMS:KO` affiche sur l'OLED/web) si aucune
|
|
||||||
trame `$T,...*XX` valide n'est recue depuis plus de **2 secondes**
|
|
||||||
(`TmsLink::linkOk()`).
|
|
||||||
|
|
||||||
Tous les champs sont optionnels a l'envoi individuel (un champ absent
|
| Code | Signification |
|
||||||
garde sa derniere valeur connue cote ESP32), mais en pratique il est plus
|
|---|---|
|
||||||
simple d'envoyer tous les champs a chaque trame.
|
| `0` | Aucun defaut |
|
||||||
|
| `1` | EMUSTOP -- le debogueur a arrete le CPU |
|
||||||
|
| `2` | Surintensite I1 (etage 1) |
|
||||||
|
| `3` | Surintensite I2 (etage 2) |
|
||||||
|
| `4` | Temperature critique T1 (> 80 degC) |
|
||||||
|
| `5` | Temperature critique T2 (> 80 degC) |
|
||||||
|
|
||||||
|
**Priorite quand plusieurs defauts coexistent : 2 > 3 > 4 > 5 > 1.**
|
||||||
|
EMUSTOP a donc la priorite la plus BASSE malgre son numero : en
|
||||||
|
developpement il se declenche a chaque halte du debogueur et ne doit
|
||||||
|
jamais masquer une surintensite reelle.
|
||||||
|
|
||||||
|
**Il n'existe volontairement pas de code "court-circuit".** Un
|
||||||
|
court-circuit franchit le meme comparateur et le meme seuil qu'une
|
||||||
|
surintensite ; le firmware ne dispose d'aucune information permettant de
|
||||||
|
les distinguer. Les codes 2 et 3 couvrent les deux cas.
|
||||||
|
|
||||||
|
#### Verrouillage : pas d'effacement par le protocole
|
||||||
|
|
||||||
|
Contrairement a ce que supposait une version precedente de ce document,
|
||||||
|
**un defaut ne s'efface JAMAIS automatiquement**, ni a la disparition de
|
||||||
|
sa cause, ni par commande UART. Il n'existe aucun tag `$C` permettant de
|
||||||
|
l'acquitter.
|
||||||
|
|
||||||
|
Le seul moyen de repartir est de **couper puis retablir l'alimentation**.
|
||||||
|
C'est un choix deliberé (PROMPT §8) : un defaut de puissance doit exiger
|
||||||
|
une intervention humaine et un examen de la carte.
|
||||||
|
|
||||||
|
Consequence pour l'ESP32 : tant que le TMS320 emet un `FAULT != 0`, il
|
||||||
|
continuera de l'emettre indefiniment. L'IHM doit donc afficher ce code de
|
||||||
|
maniere persistante, sans attendre un retour spontane a 0.
|
||||||
|
|
||||||
|
> Rappel (PROMPT §2) : la protection reelle -- comparateurs + Trip Zone
|
||||||
|
> materiel -- ne depend jamais de cette liaison UART. `FAULT` n'est qu'un
|
||||||
|
> report d'information vers l'IHM, envoye apres coup ; la coupure a deja
|
||||||
|
> eu lieu en materiel avant meme que la trame ne soit construite.
|
||||||
|
|
||||||
|
#### Icone danger : pilotee par VOUT, jamais par FAULT
|
||||||
|
|
||||||
|
L'avertissement haute tension doit dependre **uniquement de `VOUT`**, et
|
||||||
|
rester affiche independamment de l'etat de `FAULT`.
|
||||||
|
|
||||||
|
Un defaut ne decharge pas le condensateur de sortie. Apres une coupure,
|
||||||
|
`HV_EN` isole la charge mais les 400 V restent presents. Faire disparaitre
|
||||||
|
l'icone danger au moment d'un defaut reviendrait a rassurer l'operateur
|
||||||
|
precisement quand le risque est maximal.
|
||||||
|
|
||||||
|
La carte de puissance comporte deux dispositifs complementaires :
|
||||||
|
|
||||||
|
- un **bleeder de 1 MOhm avec LED rouge en serie**, indication passive
|
||||||
|
qui reste valable alimentation coupee (~42 s pour passer sous 50 V) ;
|
||||||
|
- un **circuit de decharge actif** (MOSFET + 47 kOhm, ~2 s de 500 V a
|
||||||
|
50 V), commande par le TMS320 sur GPIO5 / broche 40, **a logique
|
||||||
|
inversee** : il conduit des que la commande disparait, donc au reset,
|
||||||
|
en cas de plantage et alimentation coupee.
|
||||||
|
|
||||||
|
**Frequence d'envoi : toutes les 300 ms.** L'ESP32 considere la liaison
|
||||||
|
perdue (`TMS:KO`) si aucune trame `$T` valide n'est recue depuis plus de
|
||||||
|
**2 secondes**. Le TMS320 applique le meme timeout dans l'autre sens.
|
||||||
|
|
||||||
|
Tous les champs sont optionnels individuellement (un champ absent garde
|
||||||
|
sa derniere valeur cote ESP32) ; en pratique le TMS320 les envoie tous.
|
||||||
|
Si une trame devait depasser la longueur maximale, le firmware abandonne
|
||||||
|
des champs entiers plutot que d'en tronquer un.
|
||||||
|
|
||||||
|
### Calibration des mesures analogiques (cote TMS320)
|
||||||
|
|
||||||
|
Coefficients appliques sur la lecture ADC (`Vadc`, en volts) pour obtenir
|
||||||
|
la valeur physique. **Valeurs mesurees sur la carte reelle**, sauf mention
|
||||||
|
contraire -- voir `mesure-cartepuissance.md` pour la tracabilite.
|
||||||
|
|
||||||
|
| Grandeur | Pleine echelle (3,3 V) | Relation | Statut |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `VIN` | 36,7 V | `VIN = Vadc x 11,11` | mesure |
|
||||||
|
| `IIN` | 3,97 A | `IIN = Vadc x 1,2019` | mesure (1 point) |
|
||||||
|
| `V1` | 103,1 V (usage limite a 50 V) | `V1 = Vadc x 31,25` | mesure |
|
||||||
|
| `VOUT` | 600 V | `VOUT = Vadc x 181,82` | mesure |
|
||||||
|
| `IOUT` | 50 mA (a confirmer) | `IOUT = Vadc x 0,016667` | **a mesurer** |
|
||||||
|
| `I1` | 5,15 A | `I1 = (Vadc - 0,0473) / 0,631` | **provisoire (MCP6001)** |
|
||||||
|
| `I2` | 5,12 A | `I2 = (Vadc - 0,0340) / 0,637` | **provisoire (MCP6001)** |
|
||||||
|
|
||||||
|
**Notes :**
|
||||||
|
|
||||||
|
- **I1/I2** : le gain differe d'environ 1 % entre les deux voies et chaque
|
||||||
|
voie a un offset non nul a courant nul (47,3 / 34,0 mV). Ne jamais
|
||||||
|
utiliser un gain unique pour les deux. Ces valeurs sont mesurees avec
|
||||||
|
les **MCP6001 de banc** ; le composant definitif est le TLV9151. Le gain
|
||||||
|
devrait rester valable (fixe par le reseau de resistances) mais
|
||||||
|
**l'offset devra etre integralement remesure**.
|
||||||
|
- **MCP6001, limite de bande passante** : 1 MHz de produit gain-bande a un
|
||||||
|
gain de ~31 plafonne vers 32 kHz. Pour proteger un decoupage a 200 kHz,
|
||||||
|
les 30 ns du comparateur ne servent a rien si l'ampli en amont met des
|
||||||
|
dizaines de microsecondes. **La protection rapide n'est pas reellement
|
||||||
|
rapide tant que le MCP6001 est en place.**
|
||||||
|
- **NTC** : montage 3,3 V -- NTC -- R_fixe -- 0 V, mesure au point milieu.
|
||||||
|
La NTC etant cote 3,3 V, la relation est
|
||||||
|
`R_ntc = R_fixe x (VREF - Vadc) / Vadc`. Les thermistances sont a 5 mm
|
||||||
|
des MOSFET : elles mesurent le cuivre, pas la jonction, avec un ecart
|
||||||
|
statique et un retard thermique notables. Le seuil de 80 degC est donc
|
||||||
|
**provisoire**, a recaler sur la temperature de boitier en charge.
|
||||||
|
- **IOUT** : aucune mesure reelle a ce jour.
|
||||||
|
|
||||||
### Commande : ESP32 -> TMS320 (periodique + a chaque changement)
|
### Commande : ESP32 -> TMS320 (periodique + a chaque changement)
|
||||||
|
|
||||||
@ -78,61 +175,29 @@ $C,HT=1,PWM1=1,PWM2=0*3E
|
|||||||
| `PWM2` | 0 ou 1 | PWM etage 2 activee/desactivee |
|
| `PWM2` | 0 ou 1 | PWM etage 2 activee/desactivee |
|
||||||
|
|
||||||
L'ESP32 envoie cette trame toutes les **500 ms**, et immediatement a
|
L'ESP32 envoie cette trame toutes les **500 ms**, et immediatement a
|
||||||
chaque changement d'etat depuis l'IHM (OLED/web). Le TMS320 doit
|
chaque changement depuis l'IHM. Le TMS320 applique le dernier etat recu et
|
||||||
simplement appliquer le dernier etat recu et valide (checksum correct).
|
valide. Les trois tags doivent etre presents, sinon la trame est ignoree.
|
||||||
|
|
||||||
## Calcul du checksum
|
## Calcul du checksum
|
||||||
|
|
||||||
XOR de tous les octets entre `$` et `*` (exclus), formate en hexadecimal
|
XOR de tous les octets entre `$` et `*` (exclus), en hexadecimal majuscule
|
||||||
majuscule sur 2 chiffres (`%02X`).
|
sur 2 chiffres (`%02X`).
|
||||||
|
|
||||||
Exemple en C pour une trame a construire :
|
Pour la reception : meme calcul, comparaison au checksum recu, trame
|
||||||
|
ignoree silencieusement si ca ne correspond pas.
|
||||||
|
|
||||||
```c
|
> **Piege rencontre cote TMS320, a ne pas reproduire.** Decoder le
|
||||||
uint8_t checksum_of(const char *s, int len) {
|
> checksum avec `strtol` sur un buffer non termine par `\0` fait lire
|
||||||
uint8_t cs = 0;
|
> au-dela de la trame. Et sur C28x, `uint8_t` fait 16 bits (pas
|
||||||
for (int i = 0; i < len; i++) cs ^= (uint8_t)s[i];
|
> d'adressage par octet) : un cast `(uint8_t)` ne tronque donc rien, et un
|
||||||
return cs;
|
> `"7D"` suivi d'un residu `"7D"` donne 0x7D7D, conserve tel quel. Toute
|
||||||
}
|
> trame etait rejetee. Decoder **exactement deux chiffres**, de maniere
|
||||||
|
> bornee.
|
||||||
// Construction d'une trame telemetrie :
|
|
||||||
char body[128];
|
|
||||||
int n = sprintf(body, "T,FREQ1=%.0f,FREQ2=%.0f,DUTY1=%.1f,DUTY2=%.1f,"
|
|
||||||
"VIN=%.1f,IIN=%.2f,V1=%.1f,I1=%.2f,T1=%.1f,"
|
|
||||||
"VOUT=%.1f,I2=%.2f,T2=%.1f,IOUT=%.2f",
|
|
||||||
freq1, freq2, duty1, duty2, vin, iin, v1, i1, t1, vout, i2, t2, iout);
|
|
||||||
uint8_t cs = checksum_of(body, n);
|
|
||||||
char frame[160];
|
|
||||||
sprintf(frame, "$%s*%02X\n", body, cs);
|
|
||||||
// envoyer frame sur l'UART
|
|
||||||
```
|
|
||||||
|
|
||||||
Pour la reception des trames `$C,...*XX` : appliquer le meme calcul sur
|
|
||||||
la partie entre `$` et `*`, comparer au checksum recu, et ignorer la
|
|
||||||
trame si ca ne correspond pas (trame corrompue).
|
|
||||||
|
|
||||||
## Cote ESP32 : ce qui existe deja
|
|
||||||
|
|
||||||
- `include/protocol.h` : structures `Telemetry` et `CommandState`,
|
|
||||||
description du protocole (source de verite en cas de doute).
|
|
||||||
- `src/tms_link.cpp` : parsing des trames `$T,...`, envoi des trames
|
|
||||||
`$C,...`, gestion du timeout de liaison. Contient aussi
|
|
||||||
`updateSimulation()`, qui simule des valeurs realistes (utile comme
|
|
||||||
reference de plage de valeurs attendues : `Vin` ~400V, `Iin` ~1.2A,
|
|
||||||
`V1`/`Vout` ~200V, `I1`/`I2` ~2.5A, `T1`/`T2` ~40°C).
|
|
||||||
- `include/config.h` : `TMS_DUMMY_MODE` (actuellement `true`) fait
|
|
||||||
tourner l'ESP32 sur la simulation interne au lieu de lire l'UART reel.
|
|
||||||
**A passer a `false` une fois le firmware TMS320 pret et teste**, pour
|
|
||||||
activer la reception reelle des trames `$T,...*XX`.
|
|
||||||
|
|
||||||
## Points de vigilance
|
## Points de vigilance
|
||||||
|
|
||||||
- Le format hexadecimal du checksum doit etre en **majuscules** sur 2
|
- Checksum en **majuscules** sur 2 chiffres, sinon rejet silencieux cote
|
||||||
chiffres (`%02X`), sinon la trame sera rejetee cote ESP32 (silencieux,
|
ESP32 -- la telemetrie n'avance simplement plus.
|
||||||
pas d'erreur visible — la telemetrie n'avancera simplement pas).
|
- Terminer par `\n` uniquement (`\r` tolere).
|
||||||
- Terminer chaque trame par `\n` uniquement (le `\r` est tolere/ignore
|
- Longueur de ligne maximale : **200 caracteres** (`g_lineBuf[200]` cote
|
||||||
cote ESP32 mais pas necessaire).
|
ESP32, `UART_LINE_MAX` cote TMS320).
|
||||||
- Ne pas depasser une longueur de ligne de 160 caracteres (buffer fixe
|
|
||||||
cote ESP32, `g_lineBuf[160]` dans `tms_link.cpp`).
|
|
||||||
- Verifier au multimetre/oscilloscope le niveau logique du TMS320 avant
|
|
||||||
de le relier a l'ESP32-C3 (3,3V attendu).
|
|
||||||
|
|||||||
202
docs/mesure-cartepuissance.md
Normal file
202
docs/mesure-cartepuissance.md
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
# Mesures carte puissance — TMS320F28027 dual boost
|
||||||
|
|
||||||
|
Suivi des mesures de calibration effectuées sur la carte élévateur (à moitié
|
||||||
|
complète : composants de puissance et drivers MOSFET pas encore montés).
|
||||||
|
Ce document est la source pour remplir `calib.h` dans le firmware. Les
|
||||||
|
valeurs numériques finales à utiliser en code sont dans
|
||||||
|
`PROMPT-claude-code-TMS320.md` (section 5) ; ce fichier-ci garde la trace
|
||||||
|
des mesures brutes et de leur contexte.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Chaînes de mesure de tension
|
||||||
|
|
||||||
|
Méthode : alimentation de labo réglée à une tension connue, lecture de la
|
||||||
|
tension de sortie du pont diviseur au multimètre (avant l'ADC).
|
||||||
|
|
||||||
|
| Voie | Point de mesure | Coefficient mesuré (Vadc/Vréel) | Gain (V/V) | Pleine échelle (3,3 V) | Statut |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| VIN (V_batt) | pin 10 | 0,09 | 11,11 | 36,7 V | ✅ mesuré |
|
||||||
|
| V1 (V_inter) | pin 16 | 0,032 | 31,25 | 103,1 V | ✅ mesuré |
|
||||||
|
| VOUT (V_HT) | pin 14 | 0,0055 | 181,82 | 600 V | ✅ mesuré |
|
||||||
|
|
||||||
|
**Remarques :**
|
||||||
|
- VIN et V1 tombent exactement sur les valeurs théoriques calculées à la
|
||||||
|
conception (11,11 et 31,25) — le pont a été monté avec les bonnes valeurs
|
||||||
|
de résistances.
|
||||||
|
- VOUT diffère de 1,8 % de la valeur théorique (178,6 → 181,82), imputable
|
||||||
|
à la tolérance des résistances réelles. Sans conséquence : la pleine
|
||||||
|
échelle réelle (600 V) reste au-dessus de l'objectif (400 V max), avec
|
||||||
|
même un peu plus de marge que prévu.
|
||||||
|
- V1 max visé = 50 V → seulement ~1,6 V sur l'ADC (48 % de la plage), pas
|
||||||
|
de saturation, résolution confirmée suffisante.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Chaîne de mesure de courant d'entrée (IIN)
|
||||||
|
|
||||||
|
Méthode : courant imposé au primaire, lecture de la tension de sortie de
|
||||||
|
l'ampli de mesure au multimètre.
|
||||||
|
|
||||||
|
| Point | Valeur |
|
||||||
|
|---|---|
|
||||||
|
| Mesure | 250 mA → 0,208 V en sortie ampli |
|
||||||
|
| Gain calculé | 0,832 V/A |
|
||||||
|
| Gain inverse | 1,2019 A/V |
|
||||||
|
| Pleine échelle (3,3 V) | 3,97 A |
|
||||||
|
|
||||||
|
Un seul point mesuré (pas de vérification de linéarité multi-points comme
|
||||||
|
pour les shunts MOSFET). Cohérent avec le courant d'entrée nominal attendu
|
||||||
|
(~590 mA pour ~5 W de charge côté HT), bonne marge avant saturation.
|
||||||
|
|
||||||
|
**Reste à faire** : idéalement un second point de mesure pour confirmer la
|
||||||
|
linéarité et détecter un éventuel offset (mesure faite à un seul courant,
|
||||||
|
donc le calcul suppose une caractéristique passant par zéro — à vérifier).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Chaînes de mesure de courant shunt MOSFET (I1, I2) — protection rapide
|
||||||
|
|
||||||
|
⚠️ **Mesures faites avec le MCP6001 monté provisoirement sur le banc de
|
||||||
|
test.** Le composant final prévu est le TLV9151 (meilleur offset, meilleure
|
||||||
|
bande passante). Le gain (fixé par le réseau de résistances RF/RG) doit
|
||||||
|
rester valable après le remplacement ; l'offset devra être entièrement
|
||||||
|
remesuré.
|
||||||
|
|
||||||
|
Méthode : courant imposé dans chaque shunt (0,02 Ω), lecture au
|
||||||
|
multimètre de la tension aux bornes du shunt (`V_Rshunt`) et de la sortie
|
||||||
|
ampli-op avant ADC (`V_shunt_adc`), à quatre points (0, 0,5, 1, 2 A).
|
||||||
|
|
||||||
|
### Données brutes
|
||||||
|
|
||||||
|
**Shunt 1 (étage 1) :**
|
||||||
|
|
||||||
|
| I (A) | V_Rshunt (mV) | V_shunt1_adc (V) |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | — | 0,0473 |
|
||||||
|
| 0,5 | 10,3 | 0,367 |
|
||||||
|
| 1 | 20,38 | 0,682 |
|
||||||
|
| 2 | 40,9 | 1,31 |
|
||||||
|
|
||||||
|
**Shunt 2 (étage 2) :**
|
||||||
|
|
||||||
|
| I (A) | V_Rshunt (mV) | V_shunt2_adc (V) |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | — | 0,0340 |
|
||||||
|
| 0,5 | 10,48 | 0,357 |
|
||||||
|
| 1 | 20,58 | 0,674 |
|
||||||
|
| 2 | 40,76 | 1,31 |
|
||||||
|
|
||||||
|
### Résultats (régression linéaire sur les 4 points)
|
||||||
|
|
||||||
|
| Voie | Offset (I=0) | Gain (V/A) | Gain équivalent shunt×ampli (V/V) | Gain inverse (A/V) | Pleine échelle (3,3 V) |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| I1 (étage 1) | 47,3 mV | 0,631 | ≈ 31,5 | 1,585 | 5,15 A |
|
||||||
|
| I2 (étage 2) | 34,0 mV | 0,637 | ≈ 31,8 | 1,570 | 5,12 A |
|
||||||
|
|
||||||
|
**Formules de conversion (provisoires, MCP6001) :**
|
||||||
|
```
|
||||||
|
I1 = (Vadc − 0,0473) / 0,631
|
||||||
|
I2 = (Vadc − 0,0340) / 0,637
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remarques :**
|
||||||
|
- Très bonne linéarité sur les 4 points des deux voies.
|
||||||
|
- Écart de gain d'environ 1 % entre les deux voies — attribuable à la
|
||||||
|
tolérance des résistances de gain, propre à chaque canal. Ne pas
|
||||||
|
utiliser un gain unique moyenné : garder deux jeux de constantes séparés
|
||||||
|
dans `calib.h`.
|
||||||
|
- Le gain mesuré (~31,5-31,8) est proche de la valeur visée à la
|
||||||
|
conception (31), mais **s'écarte de l'hypothèse initiale utilisée pour
|
||||||
|
calculer le seuil DAC** (qui supposait un gain de 30 pile). Voir §5 pour
|
||||||
|
la correction.
|
||||||
|
- Les deux offsets (34-47 mV) sont nettement plus élevés que le Vos
|
||||||
|
typique du MCP6001 seul à ce gain — probablement une combinaison de
|
||||||
|
l'offset ampli réel et d'un petit décalage du pont/de la référence.
|
||||||
|
Sans conséquence pratique : l'auto-zéro logiciel prévu au boot du
|
||||||
|
firmware absorbe cet écart automatiquement, quelle que soit son origine.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Chaîne de mesure de courant de sortie (IOUT)
|
||||||
|
|
||||||
|
**Non mesurée.** Reste à faire — même méthode que pour IIN (courant imposé
|
||||||
|
côté charge après le switch de sortie, lecture de la tension ampli-op).
|
||||||
|
Valeur théorique provisoire dans `calib.h` : 3,0 V @ 50 mA → gain
|
||||||
|
0,016667 A/V (à confirmer/remplacer par une mesure réelle).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Seuil de protection — recalcul avec les gains mesurés
|
||||||
|
|
||||||
|
Le calcul initial du code DAC (`DACVAL`) pour le seuil de 3 A avait été
|
||||||
|
fait en supposant un gain exactement égal à 30 (shunt 0,02 Ω × ampli-op
|
||||||
|
×30), donnant `Vadc = 1,8 V` à 3 A. **Cette hypothèse est fausse** : le gain
|
||||||
|
réel mesuré est ~31,5-31,8, donc en réalité `1,8 V` correspondait à un
|
||||||
|
seuil réel plus proche de 3,3 A que de 3 A. Non dangereux (la protection
|
||||||
|
aurait juste déclenché un peu tard), mais corrigé avant tout flashage.
|
||||||
|
|
||||||
|
**Valeurs recalculées avec les gains et offsets mesurés (§3) :**
|
||||||
|
|
||||||
|
```
|
||||||
|
Seuil 3 A, comparateur 1 (I-shunt1) :
|
||||||
|
Vadc = 0,0473 + 3 × 0,631 = 1,940 V
|
||||||
|
DACVAL = round(1,940 × 1023 / 3,3) = 601
|
||||||
|
|
||||||
|
Seuil 3 A, comparateur 2 (I-shunt2) :
|
||||||
|
Vadc = 0,0340 + 3 × 0,637 = 1,945 V
|
||||||
|
DACVAL = round(1,945 × 1023 / 3,3) = 603
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ Ces deux valeurs sont provisoires (MCP6001).** Elles devront être
|
||||||
|
recalculées avec les mêmes formules dès que le gain et l'offset seront
|
||||||
|
remesurés sur le TLV9151. Le firmware ne doit jamais figer `DACVAL` en
|
||||||
|
dur : le calculer par macro à partir de `SAFETY_ISHUNT_THRESHOLD_A` et des
|
||||||
|
constantes de gain/offset mesurées, pour que ce remplacement futur ne
|
||||||
|
touche qu'aux valeurs de `calib.h`, pas au code.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Ce qu'il reste à faire
|
||||||
|
|
||||||
|
### Mesures à compléter
|
||||||
|
- [ ] IOUT : gain réel (un point de mesure minimum, idéalement deux)
|
||||||
|
- [ ] IIN : second point de mesure pour vérifier la linéarité/l'offset
|
||||||
|
- [ ] Chaîne NTC (Temp1, Temp2) : vérifier la valeur réelle de la
|
||||||
|
résistance fixe des ponts diviseurs (10 kΩ supposé) et, si possible,
|
||||||
|
un point de mesure à température connue pour valider la formule
|
||||||
|
Steinhart-Hart simplifiée
|
||||||
|
- [ ] I1, I2 **à refaire intégralement** une fois le TLV9151 monté (gain à
|
||||||
|
confirmer proche de ~31,5-31,8, offset à mesurer — attendu très
|
||||||
|
inférieur aux 34-47 mV actuels)
|
||||||
|
|
||||||
|
### Matériel restant à monter sur la carte élévateur
|
||||||
|
- [ ] Composants de puissance (MOSFET IPD60R360, diode SiC STPSC406,
|
||||||
|
inductances) — carte actuellement à moitié complète
|
||||||
|
- [ ] Driver de grille : **le UCC27518/19 initialement prévu ne convient
|
||||||
|
pas** (seuils d'entrée CMOS proportionnels à VDD = 12 V, un signal
|
||||||
|
3,3 V du F28027 ne les franchira jamais). Remplacer par UCC27517
|
||||||
|
(seuils CMOS/TTL indépendants de VDD, même boîtier SOT-23-5, même
|
||||||
|
brochage) — vérifier la polarité (inverseur/non-inverseur) requise
|
||||||
|
selon le sens voulu sur EN
|
||||||
|
- [ ] TLV9151 : montage définitif à la place du MCP6001 de banc
|
||||||
|
|
||||||
|
### Firmware (TMS320F28027-dualboost, côté Claude Code / CCS)
|
||||||
|
- [ ] Reporter les gains/offsets mesurés (§1-3) dans `calib.h`, avec la
|
||||||
|
structure par voie recommandée (gain, offset, seuil) plutôt que des
|
||||||
|
constantes isolées
|
||||||
|
- [ ] Vérifier que le calcul de `DACVAL` est bien fait par macro à partir
|
||||||
|
des constantes, pas en dur
|
||||||
|
- [ ] Une fois le driver de grille corrigé et les composants de puissance
|
||||||
|
montés : test matériel de l'étape 2 du firmware (sécurité) avant
|
||||||
|
toute activation du PWM — critère : `TZFRC` force les sorties à 0,
|
||||||
|
un breakpoint coupe le PWM (TZ6/OSHT6), le flag ne se réarme pas
|
||||||
|
seul
|
||||||
|
|
||||||
|
### Points de configuration matérielle en attente de confirmation
|
||||||
|
- [ ] Fréquence de découpage par étage (100 ou 200 kHz)
|
||||||
|
- [ ] Polarité réelle des LED (bleue/rouge)
|
||||||
|
- [ ] Valeur d'inductance retenue par étage (47 ou 100 µH)
|
||||||
|
- [ ] État de la liaison JTAG / UART après le dernier diagnostic (mesure
|
||||||
|
du 1,8 V sur VDD broches 32/43, recâblage croisé RX/TX) — à
|
||||||
|
confirmer que tout fonctionne avant de reprendre les tests
|
||||||
13
src/adc.c
13
src/adc.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,12 +43,20 @@ void bsp_gpio_control_init(void)
|
|||||||
// HV_EN = GPIO32 (broche 31)
|
// HV_EN = GPIO32 (broche 31)
|
||||||
GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0;
|
GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0;
|
||||||
GpioCtrlRegs.GPBDIR.bit.GPIO32 = 1;
|
GpioCtrlRegs.GPBDIR.bit.GPIO32 = 1;
|
||||||
|
|
||||||
|
// DISCHARGE = GPIO5 (broche 40)
|
||||||
|
GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 0;
|
||||||
|
GpioCtrlRegs.GPADIR.bit.GPIO5 = 1;
|
||||||
EDIS;
|
EDIS;
|
||||||
|
|
||||||
// Etat sur avant toute autre configuration.
|
// Etat sur avant toute autre configuration. La decharge est laissee
|
||||||
|
// ACTIVE : au demarrage, le condensateur de sortie peut encore etre
|
||||||
|
// charge par une session precedente, rien ne justifie de l'inhiber
|
||||||
|
// avant que la conversion ne soit reellement demandee.
|
||||||
stage_enable_set(STAGE_1, false);
|
stage_enable_set(STAGE_1, false);
|
||||||
stage_enable_set(STAGE_2, false);
|
stage_enable_set(STAGE_2, false);
|
||||||
hv_enable_set(false);
|
hv_enable_set(false);
|
||||||
|
hv_discharge_set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage_enable_set(stage_id_t stage, bool enabled)
|
void stage_enable_set(stage_id_t stage, bool enabled)
|
||||||
@ -89,6 +97,20 @@ void hv_enable_set(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hv_discharge_set(bool active)
|
||||||
|
{
|
||||||
|
// Niveau BAS = decharge active (NPN bloque, grille du MOSFET libre).
|
||||||
|
// Voir bsp_gpio.h pour le detail de la polarite inversee.
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
GpioDataRegs.GPACLEAR.bit.GPIO5 = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GpioDataRegs.GPASET.bit.GPIO5 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bsp_gpio_stage_default_override_init(void)
|
void bsp_gpio_stage_default_override_init(void)
|
||||||
{
|
{
|
||||||
EALLOW;
|
EALLOW;
|
||||||
|
|||||||
@ -36,6 +36,26 @@ void stage_enable_set(stage_id_t stage, bool enabled);
|
|||||||
// donne PAS 0 V en sortie (PROMPT §6 etape 6).
|
// donne PAS 0 V en sortie (PROMPT §6 etape 6).
|
||||||
void hv_enable_set(bool enabled);
|
void hv_enable_set(bool enabled);
|
||||||
|
|
||||||
|
// DISCHARGE (GPIO5, broche 40) : circuit de decharge rapide du condensateur
|
||||||
|
// de sortie, sur la carte de puissance. 47 kOhm en serie avec un MOSFET,
|
||||||
|
// soit ~2 s pour passer de 500 V a 50 V (tau = 0,94 s).
|
||||||
|
//
|
||||||
|
// POLARITE INVERSEE, et c'est le coeur du montage. Le GPIO pilote un NPN
|
||||||
|
// qui court-circuite la grille du MOSFET :
|
||||||
|
// niveau HAUT -> NPN conduit -> grille a la masse -> MOSFET bloque
|
||||||
|
// -> decharge INHIBEE (fonctionnement normal)
|
||||||
|
// niveau BAS, ou broche non pilotee
|
||||||
|
// -> NPN bloque -> grille tiree a 12 V (chaine 3x1 MOhm
|
||||||
|
// depuis le +500 V, ecretee par Zener) -> MOSFET conduit
|
||||||
|
// -> decharge ACTIVE
|
||||||
|
//
|
||||||
|
// GPIO5 est une broche a fonction PWM : ses pull-ups ne sont PAS actives au
|
||||||
|
// reset (PROMPT §6 etape 3), elle flotte donc. La decharge est par
|
||||||
|
// consequent active au reset, pendant un plantage, et surtout ALIMENTATION
|
||||||
|
// COUPEE -- c'est-a-dire exactement le cas ou le firmware ne peut plus rien
|
||||||
|
// garantir et ou l'operateur croit la carte inoffensive.
|
||||||
|
void hv_discharge_set(bool active);
|
||||||
|
|
||||||
// BRING-UP UNIQUEMENT -- bascule Stage1/2-default (GPIO1/GPIO3) en sortie
|
// BRING-UP UNIQUEMENT -- bascule Stage1/2-default (GPIO1/GPIO3) en sortie
|
||||||
// GPIO pilotee par logiciel, pour verifier le cablage des portes ET sans
|
// GPIO pilotee par logiciel, pour verifier le cablage des portes ET sans
|
||||||
// etage de puissance actif. Laisse les deux broches a 0.
|
// etage de puissance actif. Laisse les deux broches a 0.
|
||||||
|
|||||||
11
src/calib.h
11
src/calib.h
@ -96,7 +96,7 @@
|
|||||||
// PROVISOIRE : seuil a confirmer selon la tenue reelle du MOSFET et
|
// PROVISOIRE : seuil a confirmer selon la tenue reelle du MOSFET et
|
||||||
// l'implantation des NTC sur la carte.
|
// l'implantation des NTC sur la carte.
|
||||||
// L'hysteresis evite que l'etat oscille autour du point de bascule.
|
// L'hysteresis evite que l'etat oscille autour du point de bascule.
|
||||||
#define SAFETY_OVERTEMP_C 85.0f
|
#define SAFETY_OVERTEMP_C 80.0f
|
||||||
#define SAFETY_OVERTEMP_HYST_C 10.0f
|
#define SAFETY_OVERTEMP_HYST_C 10.0f
|
||||||
|
|
||||||
// ---- Timeout de la liaison ESP32 (PROMPT §6 etape 7) ----------------
|
// ---- Timeout de la liaison ESP32 (PROMPT §6 etape 7) ----------------
|
||||||
@ -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
|
||||||
@ -133,6 +140,6 @@
|
|||||||
((uint16_t)(((UART_LSPCLK_HZ + 4UL * UART_BAUD_RATE) / (8UL * UART_BAUD_RATE)) - 1U))
|
((uint16_t)(((UART_LSPCLK_HZ + 4UL * UART_BAUD_RATE) / (8UL * UART_BAUD_RATE)) - 1U))
|
||||||
|
|
||||||
#define UART_RX_RING_SIZE 64U
|
#define UART_RX_RING_SIZE 64U
|
||||||
#define UART_LINE_MAX 160U // limite cote ESP32 (g_lineBuf[160])
|
#define UART_LINE_MAX 200U // limite cote ESP32 (g_lineBuf[200])
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
121
src/control.c
Normal file
121
src/control.c
Normal 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
32
src/control.h
Normal 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
|
||||||
144
src/main.c
144
src/main.c
@ -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;
|
||||||
@ -27,24 +28,80 @@ static volatile bool s_send_telemetry = false;
|
|||||||
#define LINK_TIMEOUT_TICKS ((uint16_t)(UART_LINK_TIMEOUT_MS / TICK_MS))
|
#define LINK_TIMEOUT_TICKS ((uint16_t)(UART_LINK_TIMEOUT_MS / TICK_MS))
|
||||||
static volatile uint16_t s_ticks_since_cmd = LINK_TIMEOUT_TICKS;
|
static volatile uint16_t s_ticks_since_cmd = LINK_TIMEOUT_TICKS;
|
||||||
|
|
||||||
// Etat de surtemperature, avec hysteresis pour eviter le battement autour
|
// Surtemperature, suivie PAR VOIE : le protocole distingue les codes 4 (T1)
|
||||||
// du seuil.
|
// et 5 (T2), un simple maximum ne permettrait pas de les separer.
|
||||||
static bool s_overtemp = false;
|
// Hysteresis pour eviter le battement autour du seuil.
|
||||||
|
static bool s_overtemp_t1 = false;
|
||||||
|
static bool s_overtemp_t2 = false;
|
||||||
|
|
||||||
|
static bool update_one_overtemp(bool current, float temp_c)
|
||||||
|
{
|
||||||
|
if (!current)
|
||||||
|
{
|
||||||
|
return (temp_c >= SAFETY_OVERTEMP_C);
|
||||||
|
}
|
||||||
|
return (temp_c > (SAFETY_OVERTEMP_C - SAFETY_OVERTEMP_HYST_C));
|
||||||
|
}
|
||||||
|
|
||||||
static void update_overtemp(void)
|
static void update_overtemp(void)
|
||||||
{
|
{
|
||||||
float t1 = measure_temp(adc_get_raw(ADC_CH_T1));
|
s_overtemp_t1 =
|
||||||
float t2 = measure_temp(adc_get_raw(ADC_CH_T2));
|
update_one_overtemp(s_overtemp_t1, measure_temp(adc_get_raw(ADC_CH_T1)));
|
||||||
float tmax = (t1 > t2) ? t1 : t2;
|
s_overtemp_t2 =
|
||||||
|
update_one_overtemp(s_overtemp_t2, measure_temp(adc_get_raw(ADC_CH_T2)));
|
||||||
|
}
|
||||||
|
|
||||||
if (!s_overtemp)
|
// Sequence de demarrage de la conversion. Appelee au boot ET apres un
|
||||||
|
// EMUSTOP : dans les deux cas on repart du meme etat connu, on ne reprend
|
||||||
|
// jamais la conversion la ou elle s'etait arretee.
|
||||||
|
//
|
||||||
|
// Ordre impose : la decharge est inhibee AVANT d'autoriser les etages,
|
||||||
|
// sinon la conversion travaillerait contre le circuit de decharge.
|
||||||
|
static void start_conversion(void)
|
||||||
|
{
|
||||||
|
hv_discharge_set(false);
|
||||||
|
|
||||||
|
// Duty a zero d'abord : c'est le point de depart obligatoire, un
|
||||||
|
// condensateur de sortie vide provoquerait sinon un appel de courant
|
||||||
|
// destructeur (PROMPT §6 etape 6).
|
||||||
|
pwm_set_duty(STAGE_1, 0.0f);
|
||||||
|
pwm_set_duty(STAGE_2, 0.0f);
|
||||||
|
|
||||||
|
pwm_enable(STAGE_1, true);
|
||||||
|
pwm_enable(STAGE_2, true);
|
||||||
|
stage_enable_set(STAGE_1, true);
|
||||||
|
stage_enable_set(STAGE_2, true);
|
||||||
|
|
||||||
|
// Le duty est desormais pilote par control.c, qui repart du minimum.
|
||||||
|
// Les deux etages demarrent ensemble.
|
||||||
|
control_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priorite 2 > 3 > 4 > 5 > 1 : EMUSTOP est le code le moins prioritaire
|
||||||
|
// malgre son numero, pour ne jamais masquer une surintensite reelle.
|
||||||
|
static fault_code_t compute_fault_code(const safety_faults_t *f)
|
||||||
|
{
|
||||||
|
if (f->overcurrent && f->stage1_fault)
|
||||||
{
|
{
|
||||||
s_overtemp = (tmax >= SAFETY_OVERTEMP_C);
|
return FAULT_OVERCURRENT_I1;
|
||||||
}
|
}
|
||||||
else
|
if (f->overcurrent && f->stage2_fault)
|
||||||
{
|
{
|
||||||
s_overtemp = (tmax > (SAFETY_OVERTEMP_C - SAFETY_OVERTEMP_HYST_C));
|
return FAULT_OVERCURRENT_I2;
|
||||||
}
|
}
|
||||||
|
if (s_overtemp_t1)
|
||||||
|
{
|
||||||
|
return FAULT_OVERTEMP_T1;
|
||||||
|
}
|
||||||
|
if (s_overtemp_t2)
|
||||||
|
{
|
||||||
|
return FAULT_OVERTEMP_T2;
|
||||||
|
}
|
||||||
|
if (f->emustop)
|
||||||
|
{
|
||||||
|
return FAULT_EMUSTOP;
|
||||||
|
}
|
||||||
|
return FAULT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Etat sur : les deux etages inhibes ET la sortie HT coupee.
|
// Etat sur : les deux etages inhibes ET la sortie HT coupee.
|
||||||
@ -55,11 +112,18 @@ static void update_overtemp(void)
|
|||||||
// 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);
|
||||||
stage_enable_set(STAGE_2, false);
|
stage_enable_set(STAGE_2, false);
|
||||||
hv_enable_set(false);
|
hv_enable_set(false);
|
||||||
|
|
||||||
|
// Decharge active. Elle vient APRES la coupure de HV_EN : la charge est
|
||||||
|
// d'abord isolee, puis le condensateur vide en ~2 s. Sans elle, les
|
||||||
|
// 400 V resteraient presents pres d'une minute sur le seul bleeder de
|
||||||
|
// 1 MOhm, sans aucune indication une fois l'alimentation coupee.
|
||||||
|
hv_discharge_set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priorite : surintensite > surtemperature > EMUSTOP > liaison perdue.
|
// Priorite : surintensite > surtemperature > EMUSTOP > liaison perdue.
|
||||||
@ -71,7 +135,7 @@ static led_state_t compute_led_state(const safety_faults_t *f)
|
|||||||
{
|
{
|
||||||
return LED_STATE_OVERCURRENT;
|
return LED_STATE_OVERCURRENT;
|
||||||
}
|
}
|
||||||
if (s_overtemp)
|
if (s_overtemp_t1 || s_overtemp_t2)
|
||||||
{
|
{
|
||||||
return LED_STATE_OVERTEMP;
|
return LED_STATE_OVERTEMP;
|
||||||
}
|
}
|
||||||
@ -121,18 +185,15 @@ 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();
|
||||||
|
|
||||||
// ---- BRING-UP : retest PWM + ADC, puissance DECONNECTEE ---------------
|
start_conversion();
|
||||||
// A RETIRER avant toute mise sous tension de la carte de conversion.
|
|
||||||
// HV_EN et Stagex-EN restent a 0 (exclus de ce test).
|
|
||||||
pwm_set_duty(STAGE_1, 0.5f);
|
|
||||||
pwm_set_duty(STAGE_2, 0.5f);
|
|
||||||
pwm_enable(STAGE_1, true);
|
|
||||||
pwm_enable(STAGE_2, true);
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
EALLOW;
|
EALLOW;
|
||||||
PieVectTable.TINT0 = &cpu_timer0_isr;
|
PieVectTable.TINT0 = &cpu_timer0_isr;
|
||||||
@ -176,14 +237,29 @@ void main(void)
|
|||||||
// Aucun redemarrage automatique : rien ne reactive le PWM ensuite,
|
// Aucun redemarrage automatique : rien ne reactive le PWM ensuite,
|
||||||
// meme si la temperature redescend sous l'hysteresis ou si le defaut
|
// meme si la temperature redescend sous l'hysteresis ou si le defaut
|
||||||
// disparait. Il faut un reset, ou une commande explicite (etape 8).
|
// disparait. Il faut un reset, ou une commande explicite (etape 8).
|
||||||
if (faults.stage1_fault || faults.stage2_fault || s_overtemp)
|
if (faults.overcurrent || s_overtemp_t1 || s_overtemp_t2)
|
||||||
{
|
{
|
||||||
|
// Defaut de PUISSANCE : verrouille jusqu'au cycle d'alimentation
|
||||||
|
// (PROMPT §8). Aucun acquittement, ni automatique ni par UART.
|
||||||
enter_safe_state();
|
enter_safe_state();
|
||||||
}
|
}
|
||||||
else
|
else if (faults.emustop)
|
||||||
{
|
{
|
||||||
stage_enable_set(STAGE_1, true);
|
// EMUSTOP seul : ce n'est pas un defaut de puissance mais un
|
||||||
stage_enable_set(STAGE_2, true);
|
// artefact du debogueur. On autorise donc la reprise -- mais en
|
||||||
|
// repassant par la sequence de demarrage complete, jamais en
|
||||||
|
// reprenant la conversion la ou elle s'etait arretee.
|
||||||
|
//
|
||||||
|
// L'effacement ne peut aboutir qu'ici, CPU en marche : tant que
|
||||||
|
// le coeur est halte, EMUSTOP reste asserte et le drapeau se
|
||||||
|
// re-verrouille aussitot.
|
||||||
|
//
|
||||||
|
// La liaison est relancee aussi : pendant la halte l'ESP32 a
|
||||||
|
// continue d'emettre, l'anneau de reception a deborde et la
|
||||||
|
// ligne en cours est tronquee.
|
||||||
|
uart_link_restart();
|
||||||
|
safety_clear_faults();
|
||||||
|
start_conversion();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_led_set_state(compute_led_state(&faults));
|
status_led_set_state(compute_led_state(&faults));
|
||||||
@ -199,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));
|
||||||
@ -210,6 +289,7 @@ void main(void)
|
|||||||
t.i2_a = measure_i2(adc_get_raw(ADC_CH_I2));
|
t.i2_a = measure_i2(adc_get_raw(ADC_CH_I2));
|
||||||
t.t2_c = measure_temp(adc_get_raw(ADC_CH_T2));
|
t.t2_c = measure_temp(adc_get_raw(ADC_CH_T2));
|
||||||
t.iout_a = measure_iout(adc_get_raw(ADC_CH_IOUT));
|
t.iout_a = measure_iout(adc_get_raw(ADC_CH_IOUT));
|
||||||
|
t.fault = compute_fault_code(&faults);
|
||||||
|
|
||||||
uart_link_send_telemetry(&t);
|
uart_link_send_telemetry(&t);
|
||||||
s_send_telemetry = false;
|
s_send_telemetry = false;
|
||||||
@ -228,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();
|
||||||
|
|
||||||
@ -242,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;
|
||||||
|
|||||||
@ -6,6 +6,26 @@
|
|||||||
// Squelette du protocole UART TMS320<->ESP32 (voir docs/ESP32-UART.md).
|
// Squelette du protocole UART TMS320<->ESP32 (voir docs/ESP32-UART.md).
|
||||||
// Rempli/utilise a partir de l'etape 7 (uart_link.c).
|
// Rempli/utilise a partir de l'etape 7 (uart_link.c).
|
||||||
|
|
||||||
|
// Codes du champ FAULT de la trame $T (docs/ESP32-UART.md).
|
||||||
|
//
|
||||||
|
// Attention a la priorite d'affichage quand plusieurs defauts coexistent :
|
||||||
|
// elle est 2 > 3 > 4 > 5 > 1, donc EMUSTOP a la priorite la PLUS BASSE
|
||||||
|
// malgre son numero. C'est voulu : en developpement EMUSTOP se declenche a
|
||||||
|
// chaque halte du debogueur et ne doit jamais masquer une surintensite.
|
||||||
|
//
|
||||||
|
// Il n'existe volontairement AUCUN code de court-circuit : un court-circuit
|
||||||
|
// franchit le meme comparateur et le meme seuil qu'une surintensite, le
|
||||||
|
// firmware ne dispose d'aucune information permettant de les distinguer.
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FAULT_NONE = 0,
|
||||||
|
FAULT_EMUSTOP = 1,
|
||||||
|
FAULT_OVERCURRENT_I1 = 2,
|
||||||
|
FAULT_OVERCURRENT_I2 = 3,
|
||||||
|
FAULT_OVERTEMP_T1 = 4,
|
||||||
|
FAULT_OVERTEMP_T2 = 5
|
||||||
|
} fault_code_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float freq1_hz;
|
float freq1_hz;
|
||||||
@ -21,6 +41,7 @@ typedef struct
|
|||||||
float i2_a;
|
float i2_a;
|
||||||
float t2_c;
|
float t2_c;
|
||||||
float iout_a;
|
float iout_a;
|
||||||
|
fault_code_t fault;
|
||||||
} telemetry_t;
|
} telemetry_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
36
src/pwm.c
36
src/pwm.c
@ -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);
|
||||||
|
|||||||
12
src/pwm.h
12
src/pwm.h
@ -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).
|
||||||
|
|||||||
16
src/safety.c
16
src/safety.c
@ -68,6 +68,22 @@ void safety_init(void)
|
|||||||
EPwm2Regs.TZSEL.bit.OSHT6 = 1;
|
EPwm2Regs.TZSEL.bit.OSHT6 = 1;
|
||||||
EPwm2Regs.TBCTL.bit.FREE_SOFT = 0;
|
EPwm2Regs.TBCTL.bit.FREE_SOFT = 0;
|
||||||
|
|
||||||
|
// Efface un trip herite d'AVANT ce demarrage. TZFLG.OST est latche dans
|
||||||
|
// le materiel : il survit a un reset logiciel comme a un simple
|
||||||
|
// rechargement de programme, et sans ce clear le PWM resterait coupe
|
||||||
|
// sans raison visible.
|
||||||
|
//
|
||||||
|
// Sans danger : a ce stade pwm_init() a laisse les deux sorties forcees
|
||||||
|
// a l'etat bas (AQCSFRC), donc rien ne demarre. Et si la condition de
|
||||||
|
// defaut est toujours presente, le trip se re-verrouille immediatement
|
||||||
|
// -- on n'efface qu'un etat perime, jamais un defaut reel.
|
||||||
|
EPwm1Regs.TZCLR.bit.DCAEVT1 = 1;
|
||||||
|
EPwm1Regs.TZCLR.bit.OST = 1;
|
||||||
|
EPwm1Regs.TZCLR.bit.INT = 1;
|
||||||
|
EPwm2Regs.TZCLR.bit.DCAEVT1 = 1;
|
||||||
|
EPwm2Regs.TZCLR.bit.OST = 1;
|
||||||
|
EPwm2Regs.TZCLR.bit.INT = 1;
|
||||||
|
|
||||||
PieVectTable.EPWM1_TZINT = &epwm1_tzint_isr;
|
PieVectTable.EPWM1_TZINT = &epwm1_tzint_isr;
|
||||||
PieVectTable.EPWM2_TZINT = &epwm2_tzint_isr;
|
PieVectTable.EPWM2_TZINT = &epwm2_tzint_isr;
|
||||||
EDIS;
|
EDIS;
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -151,6 +151,50 @@ static int append_field(char *out, int room, const char *tag, float value,
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uart_link_restart(void)
|
||||||
|
{
|
||||||
|
// Reset logiciel du SCI : vide les FIFO et efface les etats d'erreur.
|
||||||
|
SciaRegs.SCICTL1.bit.SWRESET = 0;
|
||||||
|
SciaRegs.SCICTL1.bit.SWRESET = 1;
|
||||||
|
|
||||||
|
SciaRegs.SCIFFRX.bit.RXFIFORESET = 0;
|
||||||
|
SciaRegs.SCIFFRX.bit.RXFIFORESET = 1;
|
||||||
|
SciaRegs.SCIFFRX.bit.RXFFOVRCLR = 1;
|
||||||
|
SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1;
|
||||||
|
|
||||||
|
SciaRegs.SCIFFTX.bit.TXFIFOXRESET = 0;
|
||||||
|
SciaRegs.SCIFFTX.bit.TXFIFOXRESET = 1;
|
||||||
|
|
||||||
|
// On jette le contenu de l'anneau en avancant seulement la QUEUE.
|
||||||
|
// s_rx_head appartient a l'ISR : ne pas y toucher evite toute course.
|
||||||
|
s_rx_tail = s_rx_head;
|
||||||
|
s_line_len = 0;
|
||||||
|
|
||||||
|
// Trame d'emission en cours abandonnee : elle date d'avant l'arret.
|
||||||
|
s_tx_len = 0;
|
||||||
|
s_tx_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Champ entier (FAULT). Meme convention de bornage que append_field :
|
||||||
|
// renvoie 0 et n'ecrit rien si le champ ne tient pas.
|
||||||
|
static int append_field_int(char *out, int room, const char *tag, int value)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (room <= 1)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = snprintf(out, (size_t)room, ",%s=%d", tag, value);
|
||||||
|
if (n < 0 || n >= room)
|
||||||
|
{
|
||||||
|
out[0] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// Construit la trame et la met en attente. NE BLOQUE PAS : l'emission reelle
|
// Construit la trame et la met en attente. NE BLOQUE PAS : l'emission reelle
|
||||||
// se fait ensuite par uart_link_service_tx(), appelee quand la boucle
|
// se fait ensuite par uart_link_service_tx(), appelee quand la boucle
|
||||||
// principale a du temps disponible. Renvoie false si la trame precedente
|
// principale a du temps disponible. Renvoie false si la trame precedente
|
||||||
@ -195,6 +239,12 @@ bool uart_link_send_telemetry(const telemetry_t *t)
|
|||||||
TX_ADD("T2", t->t2_c, 1);
|
TX_ADD("T2", t->t2_c, 1);
|
||||||
TX_ADD("IOUT", t->iout_a, 2);
|
TX_ADD("IOUT", t->iout_a, 2);
|
||||||
|
|
||||||
|
{
|
||||||
|
int added_ = append_field_int(&s_tx_frame[n], TX_ROOM(), "FAULT",
|
||||||
|
(int)t->fault);
|
||||||
|
if (added_ == 0) { fields_dropped++; } else { n += added_; }
|
||||||
|
}
|
||||||
|
|
||||||
#undef TX_ADD
|
#undef TX_ADD
|
||||||
#undef TX_ROOM
|
#undef TX_ROOM
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,16 @@
|
|||||||
|
|
||||||
void uart_link_init(void);
|
void uart_link_init(void);
|
||||||
|
|
||||||
|
// Remet la liaison a plat sans reconfigurer le baud ni les broches :
|
||||||
|
// reset logiciel du SCI, vidage des FIFO, abandon de la ligne en cours
|
||||||
|
// d'assemblage et de la trame en attente d'emission.
|
||||||
|
//
|
||||||
|
// A appeler apres une interruption prolongee du CPU (EMUSTOP) : pendant la
|
||||||
|
// halte l'ESP32 a continue d'emettre, l'anneau de reception a deborde et
|
||||||
|
// la ligne en cours est tronquee. Repartir propre evite de traiter des
|
||||||
|
// fragments anterieurs a l'arret.
|
||||||
|
void uart_link_restart(void);
|
||||||
|
|
||||||
// Construit une trame $T,...*XX et la met en attente (docs/ESP32-UART.md).
|
// Construit une trame $T,...*XX et la met en attente (docs/ESP32-UART.md).
|
||||||
// NE BLOQUE PAS : rien n'est emis ici, c'est uart_link_service_tx() qui
|
// NE BLOQUE PAS : rien n'est emis ici, c'est uart_link_service_tx() qui
|
||||||
// alimente la ligne ensuite. Renvoie false si la trame precedente n'est pas
|
// alimente la ligne ensuite. Renvoie false si la trame precedente n'est pas
|
||||||
|
|||||||
Reference in New Issue
Block a user