Forum: Mikrocontroller und Digitale Elektronik Versionsinformation richtig in FW ablegen


von Claudio F. (zunge)


Lesenswert?

Hallo Zusammen

Folgendes Szenario:

Ich habe auf einem STM32F100 (mit 128kB Flash) einen Bootloader und eine 
Firmware. Bootloader ab 0x08000000, FW ab 0x08004000, Log-Daten ab 
0x08014000 bis zum Flashende. Compiliert und Entwickelt wird mit Keil.

Ich möchte nun via Bootloader die Log-Daten an einen PC senden. Dazu 
hätte ich gerne die FW-Version mit welcher die Log-Daten aufgezeichnet 
wurden.

Wie macht Ihr das bei euren Projekten mit Bootloader?

- eine Konstante mit fixer Adresse in der FW, damit der Bootloader diese 
einfach auslesen/finden kann?
1
const uint16_t fwVersion __attribute__((at(FW_VERSION_ADD))) = FW_VERSION ;
- eine Flashpage reservieren für die Versionsinformation?
- die Checksumme über den FW-Bereich als Versionsinformation?
- Konstruckt aus MagicNumber und Version, welches im FW-Bereich gefunden 
werden kann?
- Andere Vorschläge?

Die Version mit der Konstanten sah am Anfang verlockend aus, allerdings 
funktioniert sie nur mit Hindernissen (eigens Linker-Skript). Ich habe 
die Konstante ans Ende des FW-Flashbereichs legen wollen, da hat mir 
aber der Kompiler noch Initialisierungs-Code dahinter geschoben und 
somit in den Log-Daten Bereich. Also müsste ich via Linker-Skript eine 
Section für die Konstante am Ende hinzufügen. Unschön ...

Was haltet Ihr für den besten Weg?

Gruess Claudio

von x^2 (Gast)


Lesenswert?

Die Firmware ist mit einem Descriptor versehen, der beim Update (via 
Bootloader) von diesem in eine separate Flash-Page übertragen wird, die 
auch Prüfsummen, Einsprungadresse usw. enthält.

von Walter T. (nicolas)


Lesenswert?

Bei mir wird die Versionsnummer vom Subversion erzeugt und direkt als 
Konstante einkompiliert, lässt sich dann auch manuell vom Nutzer im 
Infoscreen abfragen.

von Stefan F. (Gast)


Lesenswert?

Ich würde sie einfach direkt in den Quelltext schreiben.

Sobald eine Änderung den ersten groben Test überstanden hat, wird die 
Nummer aktualisiert, bevor man den Code bzw die Firmware weiter gibt.

von Claudio F. (zunge)


Lesenswert?

x^2 schrieb:
> Die Firmware ist mit einem Descriptor versehen, der beim Update (via
> Bootloader) von diesem in eine separate Flash-Page übertragen wird, die
> auch Prüfsummen, Einsprungadresse usw. enthält.

Ok, universell, braucht aber separate Flash Page. Gut.

Walter T. schrieb:
> Bei mir wird die Versionsnummer vom Subversion erzeugt und direkt als
> Konstante einkompiliert, lässt sich dann auch manuell vom Nutzer im
> Infoscreen abfragen.

Das beantwortet leider meine Fragen nach wie es in der FW abgelegt wird 
nicht. Wir machen das aber mit der Versionsvergabe auch so.

von Claudio F. (zunge)


Lesenswert?

x^2 schrieb:
> Die Firmware ist mit einem Descriptor versehen, der beim Update (via
> Bootloader) von diesem in eine separate Flash-Page übertragen wird, die
> auch Prüfsummen, Einsprungadresse usw. enthält.

wie bildest du den Descriptor in der FW ab, so dass der Bootlader diesen 
aus der FW extrahieren kann? oder wird der sepparat an den Bootloader 
übermittelt?

von Walter T. (nicolas)


Lesenswert?

Claudio F. schrieb:
> wie es in der FW abgelegt wird

Ich verstehe die Frage nicht. Die Versionsnummer liegt wie alle anderen 
String Literals irgendwo in der data section, so wie alle anderen 
Lookup-Tabellen, Bitmaps etc. auch.

von x^2 (Gast)


Lesenswert?

Claudio F. schrieb:
> Ok, universell, braucht aber separate Flash Page. Gut.

Braucht man sowieso: Checkt dein Bootloader gar nicht die Prüfsumme(n) 
der Firmware? Wo ist diese gespeichert? Was ist mit Einsprungadresse, 
Basisaddresse der Interrupt-Vektortabelle? Wenn das alles fix verdrahtet 
an Adresse XY in der Firmware steht oder als bekannt vorausgesetzt wird, 
kann man dieses Prinzip natürlich auch für die Versionsinfo übernehmen.

[Prüfsummen (Mehrzahl) da die Firmware durchaus segmentiert sein kann, 
also über größere Lücken im Adressraum verteilt ist. Ein Spezialfall, 
aber bei mir tatsächlich der Fall.]

von x^2 (Gast)


Lesenswert?

Claudio F. schrieb:
> wie bildest du den Descriptor in der FW ab, so dass der Bootlader diesen
> aus der FW extrahieren kann? oder wird der sepparat an den Bootloader
> übermittelt?

Der Descriptor existiert unabhängig von der Firmware (=Binärcode). Er 
wird in das Format eingebracht, das beim Firmware-Update an den 
Bootloader übertragen wird. Der Bootloader extrahiert daraus den 
Descriptor und speichert ihn.

von Claudio F. (zunge)


Lesenswert?

Walter T. schrieb:
> Claudio F. schrieb:
>> wie es in der FW abgelegt wird
>
> Ich verstehe die Frage nicht. Die Versionsnummer liegt wie alle anderen
> String Literals irgendwo in der data section, so wie alle anderen
> Lookup-Tabellen, Bitmaps etc. auch.

Wie findet der Bootloader dann dieses String-Literal? Dieses kann ja vom 
Linker irgendwo plaziert werden. Deshalb die Frage wie man das am besten 
macht ... und nein, der Bootloader kennt keine Funktionen der FW, also 
getVersion() hätte das gleiche Problem wie eine Konstante ...

von Walter T. (nicolas)


Lesenswert?

Ah, Kaffee ist eine magische Flüssigkeit. Ich habe die Frage 
nachträglich dann doch verstanden, nachdem sie gemütlich in die Tasse 
träufelte.

Ich habe mich damals entschieden, dass der Bootloader die 
Firmware-Version nicht kennen muss. Der soll gefälligst einfach alles 
draufschieben, was er soll.

...

Wie wäre es mit einer ungenutzten ISR? Die Speicheradressen stehen 
bombenfest. Dann wenn die Get-Funktion eine ISR ist, dürfte das 
innerhalb der Prozessor-Familie sehr portabel sin.

von Claudio F. (zunge)


Lesenswert?

Walter T. schrieb:
> Ah, Kaffee ist eine magische Flüssigkeit. Ich habe die Frage
> nachträglich dann doch verstanden, nachdem sie gemütlich in die Tasse
> träufelte.
>
> Ich habe mich damals entschieden, dass der Bootloader die
> Firmware-Version nicht kennen muss. Der soll gefälligst einfach alles
> draufschieben, was er soll.
>
> ...
>
> Wie wäre es mit einer ungenutzten ISR? Die Speicheradressen stehen
> bombenfest. Dann wenn die Get-Funktion eine ISR ist, dürfte das
> innerhalb der Prozessor-Familie sehr portabel sin.

Jaa Kaffee, gutes Stichwort :-)

hm, guter Gedanke mit den ISR-Adressen ... muss ich wohl auch bei einer 
Tasse darüber nachdenken ...

Danke für die Inputs, auch an x^2

von Vincent H. (vinci)


Lesenswert?

Bei dem Projekt an dem ich aktuell arbeite legt die Firmware ein 
Versions-Struct vor den Resetvektor an eine konstante Adresse. Ich 
versteh nicht ganz wo da ein Problem sein soll? Durch den Bootloader 
muss man das Linkerskript ohnehin anpassen?

von Bernd K. (prof7bit)


Lesenswert?

Claudio F. schrieb:
> Ich möchte nun via Bootloader die Log-Daten an einen PC senden. Dazu
> hätte ich gerne die FW-Version mit welcher die Log-Daten aufgezeichnet
> wurden.
>
> Wie macht Ihr das bei euren Projekten

Ich hab das im Makefile:
1
# generate a version.h header file with defines 
2
# for build time and git revision.
3
src/version.h: force
4
  echo "/* Generated by Makefile. Exclude this header from version control! */\n" > src/version.h
5
  echo "#ifndef _VERSION_H_" >> src/version.h
6
  echo "#define _VERSION_H_\n" >> src/version.h
7
  echo "#define GIT_REVISION 0x$(shell git rev-parse --short HEAD)" >> src/version.h
8
  echo "#define COMPILE_DATE $(shell date --utc +%s)ULL\n" >> src/version.h
9
  echo "#endif" >> src/version.h

erzeugt mir dann diesen Header:
1
/* Generated by Makefile. Exclude this header from version control! */
2
3
#ifndef _VERSION_H_
4
#define _VERSION_H_
5
6
#define GIT_REVISION 0x807f1e1
7
#define COMPILE_DATE 1551275707ULL
8
9
#endif

von Steffen R. (steffen_rose)


Lesenswert?

Was ist das eigentliche Problem? Wenn es die feste Adresse für die 
Konstante ist:

<konstante> __attribute__((at(.....)));

Wenn ich mich recht erinnere dürfen die Bereiche nicht im Scatterfile 
enthalten sein. Muss man aus der Speicherdefinition rausnehmen.

von Claudio F. (zunge)


Lesenswert?

Vincent H. schrieb:
> Bei dem Projekt an dem ich aktuell arbeite legt die Firmware ein
> Versions-Struct vor den Resetvektor an eine konstante Adresse. Ich
> versteh nicht ganz wo da ein Problem sein soll? Durch den Bootloader
> muss man das Linkerskript ohnehin anpassen?

Auch ein Gedanke dem ich noch nicht hatte, die Vectortabelle ein wenig 
nach hinten schieben und die Versionsinfo davor plazieren. Geht in Keil 
dann auch ohne Linker-Script (nur IDE Einstellungen und VECT_TAB_OFFSET 
im Code ...

Danke für den Tipp

von Bernd K. (prof7bit)


Lesenswert?

Man kann sich ja direkt hinter der Vektortabelle noch eine section 
anlegen, die liegt dann immer am selben offset und da stört sie auch 
niemanden und nimmt nicht mehr Platz weg als notwendig.

Man kann auch seinen Startup-Code so umbauen daß er das direkt hinter 
die Vektoren schreibt, dann hat man es auch an bekannten festen Offset 
und braucht überhaupt keine zusätzliche Section.

von Bernd K. (prof7bit)


Lesenswert?

Bernd K. schrieb:
> Claudio F. schrieb:
>> Ich möchte nun via Bootloader die Log-Daten an einen PC senden. Dazu
>> hätte ich gerne die FW-Version mit welcher die Log-Daten aufgezeichnet
>> wurden.
>>
>> Wie macht Ihr das bei euren Projekten
>
> Ich hab das im Makefile:

fehlt noch ein:
1
.PHONY: force

Das war weiter oben, habs nicht mitkopiert. Sorry.

von Claudio F. (zunge)


Lesenswert?

So, hab mich für eine Variante entschieden die auf einem STM32F100 mit 
Keil Sinn macht und funktioniert:

Die Vektrotabelle muss ja immer an einer geraden Adresse (1kB 
Blockgrenze) stehen. Sieht der STM32 oder CM3 so vor ...
Deshalb hab ich meine Versionsvariabel direkt hinter die Vectortabelle 
gestellt. Da die Tabelle eine fixe Grösse hat (je na Derivat 
unterschiedlich), ist die Position der Versionsinformation bekannt. Das 
Ganze dann im Scatterfile entsprechend definiert und Voila, Der 
Bootloader kann seine eigene Verison und die Version der FW lesen. Ok, 
die eigene Version ist auch anders zu lösen, funktioniert aber genau so 
gut ...

Zur Komplettierung hier noch ein Scatterfile von Keil als Beispiel:
1
; *************************************************************
2
; *** Scatter-Loading Description File generated by uVision ***
3
; *************************************************************
4
5
LR_IROM1 0x08006000 0x0000E000  {    ; load region size_region
6
  ER_IROM1 0x08006000 0x0000E000  {  ; load address = execution address
7
   *.o (RESET, +First)
8
   *(fwVersion)
9
  }
10
  ER_IROM2 +0 {
11
   *(InRoot$$Sections)
12
   .ANY (+RO)  
13
  }
14
  RW_IRAM1 0x20000000 0x00002000  {  ; RW data
15
   .ANY (+RW +ZI)
16
  }
17
}

ergibt dann im Memory so was:
1
    RESET                                    0x08006000   Section      288  startup_stm32f100xb.o(RESET)
2
    fwVersion                                0x08006120   Section        4  main.o(fwVersion)
3
usw ...

Definition in der FW:
1
const uint32_t fwVersion __attribute__((section("fwVersion"))) = FW_VERSION ;

Zugriff im BL via:
1
#define FW_VERSION_ADD  (FW_FLASH_START_PAGE_ADD + FW_VERISON_OFFSET)
2
...
3
uint32_t* fwVersion = (uint32_t*)FW_VERSION_ADD;
4
version = *fwVersion;

Danke nochmals für alle Infos und Denkanstösse ...
Claudio

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.