Adresy proměnných pro QInsight
Proč: QInsight nemá A2L. Každá proměnná je adresována absolutní
adresou objektu v obrazu vašeho firmwaru (address="0x…",
addressExtension="0" v Comm params) a tato adresa se může s každým
sestavením posunout. Balíček obsahuje dva nástroje, které adresy vyčtou
z ladicích informací DWARF v ELF souboru a vytvoří soubor pro import do
QInsight, takže žádnou adresu nepíšete ručně.
Požadavky: Python 3 a pip install pyelftools; ELF musí obsahovat ladicí
informace (-g, které preset CubeMX Debug má — Release s -g0 ne).
tools/elf_vars_scan.py — vše řídí jeden soubor JSON
Zkopírujte tools/elf_vars.template.json k vašemu projektu, např. jako
my_firmware.vars.json, a upravte jej:
{
"elf": "build/Debug/my_firmware.elf",
"folders": [ "Core/Src", "App" ],
"symbols": [ "uwTick" ],
"output": {
"csv": "my_firmware.vars.csv",
"qinsight": "my_firmware_variables.xml",
"namespace": "my_ecu"
},
"options": { "includeConst": false, "arrays": "matrix", "maxArray": 16, "all": false }
}
| Klíč | Význam |
|---|---|
elf | obraz firmwaru s ladicími informacemi. |
folders | složky zdrojů, jejichž proměnné chcete. Absolutní cesty fungují všude; relativní složka se řeší vůči souboru JSON; pokud tam neexistuje (firmware byl přeložen jinde), hledá se místo toho jako úsek cesty ve zdrojových cestách zaznamenaných v ELF — "Core/Src" pak najde D:/Projects/MyEcu/Core/Src/main.c, ať překlad běžel kdekoli. Uveďte tolik složek, kolik potřebujete. Zdroje se neparsují; složky jen vybírají, které kompilační jednotky ELF se vypíší. |
symbols | volitelný seznam názvů proměnných, které se vypíší, i když jejich kompilační jednotka leží mimo folders — např. "uwTick", 1ms tick HAL, bez výpisu celé HAL (options.all). Jen prostá globální jména. |
output.csv | tabulka všech proměnných: file;scope;name;type;size;address;volatile;collapsed;kind;elemType;elemSize;dim1;dim2 (kind = scalar nebo matrix, viz Pole, křivky a mapy). |
output.json | tytéž řádky jako JSON (volitelné). |
output.qinsight | soubor pro import do QInsight (scanner za vás spustí elf_vars_to_qinsight.py). Alespoň jeden výstup je povinný. |
output.namespace | zapíše se do každé importované proměnné (volitelné). |
options.includeConst | vypsat i const data ve flash (výchozí false — nelze je měřit ani kalibrovat). |
options.arrays | "matrix" (výchozí): každé číselné 1D/2D pole je jeden řádek druhu matrix — blok hodnot, křivka nebo mapa pro QInsight, přenášená jako jeden blok XCP. "expand": prvky jeden po druhém jako samostatné skalární proměnné. |
options.maxArray | při arrays = "expand": rozepsat pole až do N prvků; delší se stanou jedním sbaleným řádkem name[0..n-1] s collapsed = 1 (výchozí 16, 0 = všechny). Sbalený řádek se do QInsight neimportuje. |
options.all | ignorovat folders a vypsat každou kompilační jednotku včetně HAL a lwIP (výchozí false). |
Všechny relativní cesty jsou relativní ke složce souboru JSON, takže příkaz funguje z libovolného adresáře:
python <sdk>/tools/elf_vars_scan.py my_firmware.vars.json
Příklad obsahuje examples/nucleo_h723zg/nucleo_h723zg.vars.json
("folders": ["app"], ELF presetu Debug) a příklad bez RTOS
examples/nucleo_h723zg_baremetal/nucleo_h723zg_baremetal.vars.json:
přeložte příklad, spusťte nad tímto souborem scanner a získáte skalární
proměnné demo signálů s adresami, např. gDemoSignals.channels_[0].value
na 0x2400005C v přiloženém sestavení Debug (ověřte proti vlastnímu
sestavení), a tři maticové objekty z demo_map.c.
Jména členů struktur a prvků polí se pro QInsight zplošťují
(gDemoSignals.channels_[0].value → gDemoSignals_channels_0_value);
původní cesta v C, zdrojový soubor a adresa zůstávají v popisu proměnné:
XCP: address="0x2400005C" addressExtension="0". Bitová pole se hlásí
s velikostí 0 a při importu se přeskakují — čtěte obsahující celé číslo a
použijte Bit Shift / Bit Mask v QInsight.
Pole, křivky a mapy (proměnné Matrix)
QInsight zobrazuje kalibrační mapu, křivku nebo blok hodnot
(v terminologii ASAP2 MAP / CURVE / VAL_BLK) v
Matrix controlu a přenáší jej jako
jeden blok XCP — s block módem enginu je mapa 16 × 16 float jeden
UPLOAD burst a jeden blok DOWNLOAD na zapsané okno buněk místo
stovek potvrzovaných paketů. Scanner exportuje každé číselné 1D nebo 2D
pole jako matrixVariable (options.arrays = "matrix"); rozložení,
které QInsight očekává, je jeden souvislý blok osa X, osa Y, data
s daty po řádcích (data[y][x]).
Mapu i s osami získáte ze scanu, když objekty pojmenujete podle této
konvence a udržíte je v paměti souvisle — buď jako členy jedné
struktury s pack(1), nebo jako tři po sobě jdoucí globální proměnné:
#pragma pack(push, 1)
typedef struct {
volatile uint16_t x[16]; /* X axis breakpoints, e.g. rpm */
volatile uint8_t y[16]; /* Y axis breakpoints, e.g. load [%] */
volatile float data[16][16]; /* data[y][x] */
} IgnitionMap;
#pragma pack(pop)
IgnitionMap ignitionMap; /* -> one map "ignitionMap", 1072 B block */
volatile uint16_t torqueCurve_x[8]; /* or: <name>_x, <name>_y, <name> */
volatile uint16_t torqueCurve[8]; /* -> one curve "torqueCurve" */
Pravidla, která převodník kontroluje (při porušení exportuje pole jako
samostatné bloky hodnot a vypíše varování): osa X má tolik bodů, kolik
mají data sloupců, osa Y tolik, kolik mají data řádků, a X, Y i data na
sebe v paměti navazují bez mezer (#pragma pack(1) na struktuře;
4bajtová data jako float držte na 4bajtovém offsetu — 16 + 16 bajtů os
to splňuje). Samotné pole se stane blokem hodnot (samotné 2D pole se
zploští po řádcích). Typy prvků se mapují jako u skalárů; osy mohou mít
vlastní typ (dataType u xAxis / yAxis), typ dat je výchozím typem
proměnné. Adresa bloku v popisu je adresa osy X (dat, nejsou-li
osy); proměnnou přiřaďte k protokolu XCP a zkopírujte address /
addressExtension přesně jako u skaláru. Navažte ji na periodickou
událost (polluje se jako celý blok) nebo na událost On Request (čte
se jen stiskem Read); DAQ a STIM matice nepřenášejí. Největší matice,
kterou QInsight přenese, je 64 × 64 × 4 B dat plus osy.
Příklad (app/src/demo_map.c) obsahuje tři takové objekty: qfwDemoMap
(16 × 16 float, osy uint16 / uint8), qfwDemoCurve (8 × uint16) a
qfwDemoBigMap (64 × 64 float, limit QInsight); qfwDemoMapOut je
skalár závislý na jejich buňkách, takže Watch Table ukáže účinek
zapsané buňky okamžitě. Použití v QInsight ukazuje kapitola
XCP on TCP na NUCLEO-H723ZG.
tools/elf_vars_to_qinsight.py
Převodník stojící za output.qinsight; ručně jej spouštějte jen tehdy,
když chcete jeho volby: --namespace, --strip-prefix <name> (odstranit
z zploštělých jmen úvodní jméno struktury), --keep-underscores,
--presentation <ref> (přiřadit každé proměnné prezentaci),
--address-extension.
python <sdk>/tools/elf_vars_to_qinsight.py my_firmware.vars.csv -o my_firmware_variables.xml --namespace my_ecu
Tři kroky v QInsight
- Scan po každém sestavení (
elf_vars_scan.py, výše). - Import: Home → Project Configuration → Variables → Import, vyberte XML. Import přeskakuje jména, která v projektu už existují, takže druhý import po novém sestavení nic nezduplikuje — ale ani neaktualizuje adresy. Pokud se adresy posunuly, nejprve staré proměnné smažte (nebo upravte jejich Comm params).
- Přiřaďte každou proměnnou k protokolu XCP v Project Configuration a
zkopírujte
addressaaddressExtensionz popisu do Comm params spolu sdirectionaeventRef(viz Přidání proměnné).
Důležité: Naimportovaná (nebo ručně založená) proměnná, která není přiřazena k protokolu, nemá zdroj dat a nelze ji navázat na control. Poznáte ji v Solution Exploreru: tooltip proměnné ukazuje
Source: not founda její ikona nemá modrý odznak, který přiřazené proměnné mají. Nápravou je krok 3 — přiřadit proměnnou k protokolu XCP v Project Configuration a vyplnit Comm params.
Alternativy bez nástrojů: linkerový .map vedle ELF (vyhledat symbol,
ručně přičíst offset člena — příklad offsety fixuje přes static_assert),
nebo debugger (print &gDemoSignals v gdb). Obojí scanner automatizuje.
Dále
Řešení potíží — regenerace projektu CubeMX a tabulka příznaků.

