Forum: Mikrocontroller und Digitale Elektronik CRC Summe von Konstanten zur Kompilierzeit automatisch berechnen


von Jan (Gast)


Lesenswert?

Folgende Problemstellung :

Oft muss ich Software schreiben um unterschiedliche  ASICs zu 
Testzwecken anzusteuern. (Controll Register Bits setzen, Watchdog 
bedienen, etc ).
Die MCU sendet über SPI 32Bit Kommandos an das ASIC. 29 Datenbits, die 
letzten 3 Bits sind CRC Bits.
Da die ASICs sehr komplex sind, habe ich in der Software ca. 100 
unterschiedliche Kommandos die gesendet werden. All diese 32Bits 
Kommandos sind  zur Kompilierzeit bekannt., es sind also Konstanten. Für 
die CRC Berechnung habe ich eine Funktion, die aus dem 29Bits die 3Bits 
berechnet und hinten dran hängt.
Um Zeit zu Sparren (es wird sehr viel kommuniziert, die MCU muss noch 
andere Sachen erledigen), berechne ich die crc nicht zur Laufzeit, 
sondern beim coden manuell.

Ich frage mich ob es möglich wäre die CRC bits mit dem Präprozessor zu 
berechnen ? kann man im Präprozessor schleifen implementieren? (die crc 
Berechnung wird in einer Schleife durchgeführt)

Diese Präprozessorberechnung würde man folgenderweise im Programm 
nutzen:

send_spi_32Bit(0xe5342608+CALC_3Bit_CRC(0xe5342608));
CALC_3Bit_CRC() Wäre also eine schleifenfunktion die zur kompilierzeit 
ausgeführt wird.

Nach dem Kompilieren würde Im listing an dieser Stelle dann folgendes 
stehen :
 send_spi_32Bit(0xe534260X);
X beinhaltet dann CRC plus die eine "1" (binar : 1XXX),


Ist sowas möglich?
Was kann eigentlich der Präprozessor leisten?

Das würde mir die Arbeit erleichtern, da ich oft die Kommandos verändern 
muss .


Gruss,
Jan

von Kaj (Gast)


Lesenswert?

Ueber welche Sprache reden wir denn? C oder C++?
In C++ koennte vielleicht was mit constexpr gehen.

Constexpr - Generalized Constant Expressions in C++11
http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html

constexpr specifier
http://en.cppreference.com/w/cpp/language/constexpr

Beitrag #4972486 wurde von einem Moderator gelöscht.
von Vincent H. (vinci)


Lesenswert?

Kaj schrieb:
> Ueber welche Sprache reden wir denn? C oder C++?
> In C++ koennte vielleicht was mit constexpr gehen.

Nicht nur vielleicht, die Implementierung ist banal. Sie entspricht 1:1 
der Laufzeit-Implementierung inklusive constexpr specifier.

Mit dem Präprozessor bin ich mir nicht mehr so sicher. Prinzipiell kann 
man mit jeder Menge Magie Schleifen und Loops hinbiegen, aber das is den 
Aufwand imho nicht Wert. Mal davon abgesehn, würd ich mich nicht mehr 
trauen sowas meinem Arbeitgeber zu präsentieren...

von chris (Gast)


Lesenswert?

Jan schrieb:
> Da die ASICs sehr komplex sind, habe ich in der Software ca. 100
> unterschiedliche Kommandos die gesendet werden.



Jan schrieb:
> Um Zeit zu Sparren (es wird sehr viel kommuniziert, die MCU muss noch
> andere Sachen erledigen), berechne ich die crc nicht zur Laufzeit,
> sondern beim coden manuell.


100 CRCs einmalig beim Start zu berechnen sollte wenige Millisekunden 
dauern. Ist die Power-On Zeit deines Controllers wirklich so kritisch, 
dass dafür kein Zeit ist?
Wenn du die CRCs bei jedem Senden berechnest, obwohl sie ja konstant 
bleiben, ist das natürlich Zeitverschwendung.

von Kaj (Gast)


Lesenswert?

chris schrieb:
> 100 CRCs einmalig beim Start zu berechnen sollte wenige Millisekunden
> dauern.
Aber warum sollte man das wollen, wenn man das doch schon zur 
Compiletime machen kann?

von Carl D. (jcw2)


Lesenswert?

chris schrieb:
>
>
> 100 CRCs einmalig beim Start zu berechnen sollte wenige Millisekunden
> dauern. Ist die Power-On Zeit deines Controllers wirklich so kritisch,
> dass dafür kein Zeit ist?
> Wenn du die CRCs bei jedem Senden berechnest, obwohl sie ja konstant
> bleiben, ist das natürlich Zeitverschwendung.

Nur wenn man die CRC als Bestandteil einer ID/eines Code's ins Flash 
brennen will, dann muß man das zur Compiletime berechnen. Von Hand oder 
mit einer Sprache, die das kann.

von Wilhelm M. (wimalopaan)


Lesenswert?

Carl D. schrieb:
> chris schrieb:
>>
>>
>> 100 CRCs einmalig beim Start zu berechnen sollte wenige Millisekunden
>> dauern. Ist die Power-On Zeit deines Controllers wirklich so kritisch,
>> dass dafür kein Zeit ist?
>> Wenn du die CRCs bei jedem Senden berechnest, obwohl sie ja konstant
>> bleiben, ist das natürlich Zeitverschwendung.
>
> Nur wenn man die CRC als Bestandteil einer ID/eines Code's ins Flash
> brennen will, dann muß man das zur Compiletime berechnen. Von Hand oder
> mit einer Sprache, die das kann.

Nur, was man zur Laufzeit berechnen muss(!), sollte man auch zur 
Laufzeit tun. Alles andere zur Compilezeit.

Wie oben ja schon gesagt: in C++ haben wir constexpr-function und 
neuerdings auch constexpr-lambda-expressions! Das ist echt schön. Man 
kann zur Compilezeit suchen, sortieren, ... solange das ganze eben 
insgesamt constexpr bleibt - ein reinterpret_cast<>() scheidet dann aus.
1
constexpr auto a = foo();

geht nur dann, wenn foo() tatsächlich constexpr ist und wird 
dementsprechend zur Compilezeit ausgeführt.

Zudem ist constexpr nur ein Hinweis an den Compiler, er muss also
1
auto a = foo();

nicht zwingend zur Compilezeit ausführen.

von Erich (Gast)


Lesenswert?

Hmm, 29 Bit Daten, 3 Bit "Crc".
Gibt 2^29 Möglichkeiten, und 2^3 = 8 unterschiedliche "Crc"s dazu.
Wohl kein Standard.

>ca. 100 unterschiedliche Kommandos
Wenn diese gesammelt im "Code" stehen, sollte sich irgendwie ein Macro 
erstellen lassen, das die "Crc" dazu ausrechnet und anhängt.
Wir kennen deine Programmiersprache nicht.

Alternativ über externes Programm die "Crc"s der 100 Datensätze 
ausrechnen.
Für bessere Ratschläge bräuchte es mehr Details.

Gruss

von chris (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Nur, was man zur Laufzeit berechnen muss(!), sollte man auch zur
> Laufzeit tun. Alles andere zur Compilezeit.

Prinzipiell gebe ich dir Recht.
Aber wenn der Aufwand unnötig groß ist, das zur Compilezeit zu machen, 
und es gleichzeitig kein Problem ist, es zur Laufzeit zu machen, sollte 
man es sich leichter machen.
Wenn man jetzt stundenlang rumbasteln muss bis der Compiler es macht, 
ist der Aufwand ggf. unangemessen hoch für dieses "Problem".

von Nop (Gast)


Lesenswert?

Oder Du baust Dir ein kleines CLI-Tool, was Du aus dem Buildscript 
heraus aufrufst. Das kann die Konstanten ausrechnen und ein Textfile 
ausgeben, z.B. in der gewünschten Programmiersprache. Das geht dann an 
der richtigen Stelle mit einen #include oder so rein.

Ist mit Sicherheit weniger Arbeit und nachvollziehbarer als mit dem 
Präprozessor.

von Wilhelm M. (wimalopaan)


Lesenswert?

chris schrieb:
> Wilhelm M. schrieb:
>> Nur, was man zur Laufzeit berechnen muss(!), sollte man auch zur
>> Laufzeit tun. Alles andere zur Compilezeit.
>
> Prinzipiell gebe ich dir Recht.
> Aber wenn der Aufwand unnötig groß ist, das zur Compilezeit zu machen,
> und es gleichzeitig kein Problem ist, es zur Laufzeit zu machen, sollte
> man es sich leichter machen.

Dadurch wird es nicht leichter.
Ich schreibe dieselbe Funktion / Klasse (kein Präprozessor!), nur 
verwende (!) ich sich zur Compilezeit!

> Wenn man jetzt stundenlang rumbasteln muss bis der Compiler es macht,
> ist der Aufwand ggf. unangemessen hoch für dieses "Problem".

Das verstehe ich nicht: ist doch unabhängig dann, ob Laufzeit oder 
Compilezeit.

von Wilhelm M. (wimalopaan)


Lesenswert?

Nop schrieb:
> Oder Du baust Dir ein kleines CLI-Tool,

Dann kann ich es als constexpr auch im Programm machen (sofern wir von 
C++ reden).

von Jan (Gast)


Lesenswert?

Danke schon mal für die Antworten,  die refe ist vom C. Constexpr 
funktioniert nur mit C++ wenn ich es richtig verstehe.

Vom Präprocessor lasse ich die Finger. Das wird zu kompliziert.
Ich suchte eine Lösung die auch vom jedem schnell nachvollziehbar ist.

Ich werde die CRC mit einem externen tool berechnen. Ein tool ins build 
process einbinden darf ich nicht. Ich dachte an eine Lösung mit im build 
process schon vorhanden tools etc.

Geht scheinbar nicht so ohne weiteres mit C.
Gruss

von Wilhelm M. (wimalopaan)


Lesenswert?

Jan schrieb:
> Danke schon mal für die Antworten,  die refe ist vom C. Constexpr
> funktioniert nur mit C++ wenn ich es richtig verstehe.

Ja.

>
> Vom Präprocessor lasse ich die Finger. Das wird zu kompliziert.

Gute Entscheidung, allerdings mit reinem C schwer durchhaltbar ... auch 
bei C++ braucht man immer noch #include und #pragma solange es keine 
Module gibt.

> Ich suchte eine Lösung die auch vom jedem schnell nachvollziehbar ist.
>
> Ich werde die CRC mit einem externen tool berechnen. Ein tool ins build
> process einbinden darf ich nicht. Ich dachte an eine Lösung mit im build
> process schon vorhanden tools etc.

Schreibst ein C Hilfs-Programm, das erzeugt eine header-datei ...

> Geht scheinbar nicht so ohne weiteres mit C.

Du kannst Deine C Sourcen einfach mit einem C++ Compiler übersetzen.

von Carl D. (jcw2)


Lesenswert?

Wilhelm M. schrieb:
> Jan schrieb:
>> Ich suchte eine Lösung die auch vom jedem schnell nachvollziehbar ist.
>>
>> Ich werde die CRC mit einem externen tool berechnen. Ein tool ins build
>> process einbinden darf ich nicht. Ich dachte an eine Lösung mit im build
>> process schon vorhanden tools etc.
>
> Schreibst ein C Hilfs-Programm, das erzeugt eine header-datei ...
>
>> Geht scheinbar nicht so ohne weiteres mit C.
>
> Du kannst Deine C Sourcen einfach mit einem C++ Compiler übersetzen.

Das Konzept für Compiletime und Runtime die selbe Sprache zu verwenden, 
wird sich vermutlich nicht so schnell verbreiten. Denn erst mal müssen 
mentale C und C++ Hürden genommen werden. Und erst in C++14 sind 
constexpr mächtig genug um Spaß zu machen.

von Carl D. (jcw2)


Lesenswert?

so zaubert man z.B. auf einem AVR mit gcc6.2 eine 1-wire ID ins Flash:
1
template <uint64_t V>
2
struct OwID {
3
  uint8_t value[8] = {byte(6), byte(5), byte(4), byte(3),
4
                      byte(2), byte(1), byte(0), calcCrc() };
5
6
  // access the single bytes of V at compile time
7
  static constexpr uint8_t byte(int idx) { return (V) >> (idx * 8); }
8
9
  static constexpr uint8_t crc_polynom = 0x8c;
10
11
  // calculate CRC8 of first 7 bytes of V at compile time
12
  static constexpr uint8_t calcCrc() {
13
14
    // value is not accessable/ready at compile time,
15
    // so we replicate it here
16
    uint8_t v[7] = {byte(6), byte(5), byte(4), byte(3),
17
                    byte(2), byte(1), byte(0)};
18
19
    uint8_t _crc = 0x0;
20
21
    for (int i = 0; i < 7; i++) {
22
      for (int bit = 1; bit < 256; bit *= 2) {
23
        uint8_t _actbit = ((v[i] & bit) == bit) ? 1 : 0;
24
25
        if ((_crc & 1) != _actbit)
26
          _crc = (_crc >> 1) ^ crc_polynom;
27
        else
28
          _crc = (_crc >> 1);
29
      }
30
    }
31
    return _crc;
32
  }
33
  const uint8_t operator[](const uint8_t idx) const {
34
    return pgm_read_byte(&value[idx]);
35
  }
36
};
37
38
const OwID<0x28A2D984000002> myOwId PROGMEM;
39
40
...
41
// access ID's 1st byte
42
auto id0 = myOwId[0];

von H.Joachim S. (crazyhorse)


Lesenswert?

chris schrieb:
> 100 CRCs einmalig beim Start zu berechnen sollte wenige Millisekunden
> dauern. Ist die Power-On Zeit deines Controllers wirklich so kritisch,
> dass dafür kein Zeit ist?

Mir gefällt diese Lösung auch, noch dazu wenn der Algorithmus dafür 
schon lauffähig da ist.
Kostet 100Byte RAM und winzige Zeit nach dem Reset. Wenn das beides kein 
Problem ist - warum nicht? Entwicklungszeit ist auch eine Ressource, 
einen Tod muss man sterben. Man kann vieles immer wieder und immer 
weiter optimieren, bringt aber nichts wenn man mit den Ergebnissen der 
Optimierung gar nichts anfangen kann.
Andererseits ist es natürlich trotzdem immer gut, sich auch über andere 
Lösungen Gedanken zu machen. Und wenn man weiss: es geht auch anders, 
aber im Moment brauche ich das nicht, behalte es aber im Hinterkopf ist 
das auch ein Ergebnis.

von A. S. (Gast)


Lesenswert?

Was ist denn in der Build-Umgebung?

Wir nehmen als externes Tool meist C mit gcc und lassen so quasi den 
originalen Code auf dem PC-laufen (ggf. mit Präprozessor des µC). Mit 
geringen Modifikationen und einer anderne "main" wird eine .exe erzeugt, 
die einen minimalen Header mit den Checksummen schreibt.

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.