Forum: Mikrocontroller und Digitale Elektronik STM32 Seriennummer Shrink


von Johnny S. (sgt_johnny)


Lesenswert?

Hallo Zusammen,

Ich habe hier 3x STM32L443CB Nucleo rumliegen und 2x STM32L443CB als Ic 
auf eigener Prototypenschaltung verlötet.


Es gibt im Controller eine 96bit (12byte) Unique ID. Da ich für 
Statistikzwecke eine ID benötige welche maximal 4 byte gross ist, suche 
ich nach einer Lösung um die UID vom STM32 zu shrinken.

Die ID besteht aus folgenden Bytes:

Byte 0-3 :  X-Y Position des Die auf dem Wafer
Byte 4:     Wafer-Numer
Byte 5-11:  Lot-Nummer

Anbei ein Screenshot meiner Auswertung der Controller. MCU 1 und 2 
kommen von Mouser, MCU3-5 sind Nucleos.

Was ins Auge sticht ist, das die Lot-Number jeweils die selbe ist, was 
auch in gewissem Masse logisch ist, da die IC wohl von der selben Serie 
kommen.

Auch ist relativ aufällig das Byte 1 und 3 immer 0 sind, das ist 
natürlich bei nur 5 IC's auch gut möglich das es sich um einen Zufall 
handelt. Das jedoch ein einzelner Wafer 65535 x 65535 Die's beinhaltet 
ist auch sehr unwarscheilich, weshalb ich annehme das es nur 255x255 
sein werden, und die Bit nur als Platzhalter dort sind. Auf einem Wafer 
für den STM32L433 gibt es sicher weniger Die's als für ein Modell mit 
nur wenig Funktionen & Pins.

Meine Implementation für einen Shrink der ID hätte ich aktuell so 
vorgestellt:

CRC16 aus Byte 0..4 errechnen
CRC16 aus Byte 4..11 errechnen

aus den 2x2 byte einen fiktiven uint_32 zusammensetzen also CRC1 | 
CRC2<<16

In einer Serienproduktion von Platinen, ist zudem davon auszugehen das 
die Lot Nummer wohl pro Serie zu grossen Teilen gleich ist, somit ist es 
sehr schwer ein Duplikat zu in der Lot-Nummer zu erhalten.

Was haltet ihr von der Idee? Hat jemand vielleicht schon etwas ähnliches 
Realisiert?

Möchte mir jemand allenfalls noch weitere UID's zusenden, um nach einem 
Muster zu suchen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?


von Wolfgang (Gast)


Lesenswert?

Johnny S. schrieb:
> Es gibt im Controller eine 96bit (12byte) Unique ID. Da ich für
> Statistikzwecke eine ID benötige welche maximal 4 byte gross ist, suche
> ich nach einer Lösung um die UID vom STM32 zu shrinken.

Je nach verwendetem Verfahren kann es bei einer Reduktion von 12 auf 4 
Byte passieren, dass IDs doppelt auftreten. Wenn dich diese 
Restwahrscheinlich für Mehrfachvergabe nicht stört, kannst du einen 
Hash-Wert berechnen und als ID verwenden.
Andernfalls brauchst du eine verlustfreie Kompression, was fetailierte 
Kenntnisse über die Struktur der Unique ID und/oder deiner Stichprobe 
voraus setzt.

von chris (Gast)


Lesenswert?

Ich verwende diesen code für UID, SID und RNG.
1
typedef __int128 int128_t;
2
typedef unsigned __int128 uint128_t;
3
4
uint32_t uid,sid
5
uint64_t rng;
6
#define ssid    build128(sec64(sid,xorshift(&rng)),sec64(xorshift(&rng),uid))
7
8
uint64_t xorshift64(uint64_t *state)
9
{
10
  uint64_t x = *state;  /* The state must be seeded with a nonzero value. */
11
  x ^= x >> 12; // a
12
  x ^= x << 25; // b
13
  x ^= x >> 27; // c
14
  *state = x;
15
  return x * UINT64_C(0x2545F4914F6CDD1D);
16
}
17
uint32_t xorshift(uint64_t *state) { return xorshift64(state)>>32; }
18
19
20
uint64_t  build64(uint32_t a, uint32_t b) { uint64_t c; c=a&0xAAAAAAAA|b&0x55555555|(b&0xAAAAAAAA|a&0x55555555)<<32; return c; }
21
uint128_t build128(uint64_t a, uint64_t b) { return build64(a>>32|b>>32)<<64|build64(a,b); }
22
uint64_t  sec64(uint32_t a, uint32_t b) { uint64_t r=build64(a,b)^xorshift64(&rng); uint32_t c=xorshift(&rng); uint8_t w,i; r+=c>>11; i=c>>5; i%=50; for(w=50+i;w--;) xorshift64(&r); for(w=50-i;w--;) xorshift64(&r); r+=xorshift(&r)<<(17+(++i&7); r^=xorshift(&r)>>15; return r; }
23
24
25
init_uid() {
26
  uint64_t a,b,c; uint8_t i; uint16_t w;
27
  a=build64(*uniq_id_3,*uniq_id_2);
28
  b=build64(*uniq_id_1,*uniq_id_3);
29
  j=c=xorshift(&a)<<32|xorshift(&b); 
30
  i=(w=xorshift(&c))>>10; j^=w>>3; for(w=200+i;w--;) xorshift64(&a);  for(w=0xff-i;w--;) xorshift64(&c); 
31
  i=(w=xorshift(&c))>>10; j^=w>>3; for(w=200+i;w--;) xorshift64(&b);  for(w=0xff-i;w--;) xorshift64(&c); 
32
  for(w=200+j;w--;) { xorshift64(&a); xorshift64(&b);xorshift64(&c); } 
33
  uid=xorshift(&c); 
34
  for(w=0xff-j;w--;) { xorshift64(&c); xorshift64(&c);xorshift64(&c); }
35
  sid=((xorshift(&c)^xorshift(&b)^xorshift(&a))+uid;
36
  rng= build64(xorshift(&a),xorshift(&b)); 
37
  i=xorshift64(&rng)>>10; sid^=build64(xorshift(&rng),xorshift(&c);
38
  for(w=200+i;w--;) { xorshift64(&sid); xorshift64(&sid);xorshift64(sid); }
39
  for(w=0xff-i;w--;) { xorshift64(&rng); sid+=xorshift(&c)<<(17+(++j&7); sid^=xorshift(&c)>>15; }
40
}

von Mehmet K. (mkmk)


Lesenswert?

Johnny S. schrieb:
> Meine Implementation für einen Shrink der ID hätte ich aktuell so
> vorgestellt:
>
> CRC16 aus Byte 0..4 errechnen
> CRC16 aus Byte 4..11 errechnen
>
> aus den 2x2 byte einen fiktiven uint_32 zusammensetzen also CRC1 |
> CRC2<<16

Und wieso benutzt Du nicht die interne CRC calculation unit?

von cdef (Gast)


Lesenswert?

chris schrieb:
> init_uid() {
>   uint64_t a,b,c; uint8_t i; uint16_t w;
>   a=build64(*uniq_id_3,*uniq_id_2);
>   b=build64(*uniq_id_1,*uniq_id_3);
(...)
>   for(w=0xff-i;w--;) { xorshift64(&rng); sid+=xorshift(&c)<<(17+(++j&7);
> sid^=xorshift(&c)>>15; }
> }

Für den Code würdest du bei uns sofort eine Abmahnung kassieren.

von Johnny S. (sgt_johnny)


Lesenswert?

Mehmet K. schrieb:
> Johnny S. schrieb:
>> Meine Implementation für einen Shrink der ID hätte ich aktuell so
>> vorgestellt:
>>
>> CRC16 aus Byte 0..4 errechnen
>> CRC16 aus Byte 4..11 errechnen
>>
>> aus den 2x2 byte einen fiktiven uint_32 zusammensetzen also CRC1 |
>> CRC2<<16
>
> Und wieso benutzt Du nicht die interne CRC calculation unit?

Es geht ja nicht darum wie der CRC berechnet wird, also mit welcher 
Logik, sondern um die Art

Ich hatte vor mit der internen CRC die beiden CRCs zu rechnen und dann 
zusammenzusetzen

von Chris (Gast)


Lesenswert?

Byte 0-4 ist schwach da dies xy coordinates sind.
16 bit aber bei der Die Größe sind dies nur 2 byte.
Nimm 8-11 und jeweils 0-3, 4-7

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

cdef schrieb:
> Für den Code würdest du bei uns sofort eine Abmahnung kassieren.

Bei uns würde da schon ein eiskalter Wind durch den Arbeitsvertrag 
wehen!

von W.A. (Gast)


Lesenswert?

Mw E. schrieb:
> cdef schrieb:
>> Für den Code würdest du bei uns sofort eine Abmahnung kassieren.
>
> Bei uns würde da schon ein eiskalter Wind durch den Arbeitsvertrag
> wehen!

Gegen eiskalten Wind hilft ein dickes Fell ;-)

von chris (Gast)


Lesenswert?

Man muss sehr auf Kollisionen aufpassen, z.B. die oft propagierte 
methode
von MD5 oder SHA1 ist in der Praxis unbrauchbar, da auf 32bit reduziert
extrem viele gleiche Nummern auftreten.

Ich verwende mehrere LFR welches uid relative einfach und sid
sowie rng aufwändiger generiert.

RNG wird nur intern sowie für Bootloader/Auth/Freischalungscodes 
benutzt.
Danach wird es mit rng=build64(xorshift(rng),TID) ersetzt.
TID ist eine UnixTime Konstante welche bei jedem release geändert wird
und dient auch im EEprom zum Check ob dies Initialisiert ist usw.
1
struct Uid {
2
    uint16_t X;  // x-coordinate binned code digit, 0x800a = position -10 , if msb is set, number have to be negate. 
3
    uint16_t Y;  // y-coordinate bcd encoded, center of chip is 0.
4
    uint8_t WAF;  // Wafer number
5
    char LOT[7];  // Lot number. It is possibe that it embed some non printable characters, this could be binning info to replace with space, or it could be something where some bits are lot id and some bits are speed/defect grade.
6
}; 
7
8
Batch of 100 Chips uniq X, Y and WAF data. 
9
X: 0003, 0008, 0009, 000a, 000b, 000e, 0010, 0013, 0014, 0015, 0016, 0018, 001c, 0021, 0024, 002a, 8001, 8002, 801b, 801c, 801d, 8020
10
Y: 0003, 0005, 0006, 0007, 000c, 000f, 0010, 0011, 0013, 0014, 0016, 0017, 0018, 0019, 001a, 001b, 001e, 001f, 0020, 0022, 0024, 0028, 0029, 002a, 002c, 002d, 002e, 0030, 0032, 0033, 0034, 0035, 0037, 0038, 0039, 003a, 003c, 003f, 0042, 0044, 0045, 0046, 0047, 0048, 0049, 004b, 004e
11
WAF: 0b, 0c, 0d, 0e, 18
12
13
14
0x00410024 0x3848500c 0       X: 36 Y: 65 W: 12   L:     PH8 uid: 3375-512-1140 sid: 3200-155-4603 rng: 5140-046-7130 
15
0x005f0027 0x3848500c 0        X: 39 Y: 95 W: 12   L:     PH8 uid: 0634-264-2360 sid: 3767-170-7247 rng: 4055-036-5176
16
0x20343634 0x57325707 0x00250023    X: 35 Y: 37 W: 7   L: W2W464  uid: 1057-063-1222 sid: 1054-545-3717 rng: 3630-222-5031
17
0x20343634 0x57325707 0x001F002F  X: 47 Y: 31 W: 7   L: W2W464  uid: 0766-465-5517 sid: 1763-717-6146 rng: 0421-137-5547
18
0x20343634 0x57325704 0x00220036  X: 54 Y: 34 W: 4   L: W2W464  uid: 0615-476-0473 sid: 0400-534-0605 rng: 5707-370-6725
19
0x20363532 0x50335711 0x003F0026  X: 38 Y: 63 W: 17   L: W3P256  uid: 2077-175-0241 sid: 3742-221-6705 rng: 5527-055-3510
20
0x000c0020 0x41434305 0x20303432  X: 32 Y: 12 W: 5   L: CCA240  uid: 1355-454-3223 sid: 1176-222-2612 rng: 1126-352-0045

von Johnny S. (sgt_johnny)


Angehängte Dateien:

Lesenswert?

Anbei noch das Bild, was beim ersten Post vergessen wurde.

Ich habe mir folgende Gedanken zu den Nummern gemacht:


Lotnummer: Die Lotnummer wird in der Serienproduktion vermutlich den 
grössten Teil gleich sein, beziehungsweise es wird pro Produktionsserie 
nur 2-3 verschiedene Lots geben.

Es ist stark anzunehmen das auf einenm Reel jeweils die selbe Lot-Nummer 
vorhanden ist, es macht ja keinen Sinn x-Lots zu mischen.

Somit sind die Bytes 5-11 relativ wenig unterschiedlich. Selbst wenn man 
20 verschiedene Lots kaufen würde, wäre das sicher viel.

Die Bytes 0-4 ändern jedoch stark, kombiniert mit der wenig ändernden 
Lots, gäbe dies eine Relativ einfache ID.

In meinem Fall reden wir vielleicht von insgesamt rund 25'000 
Endprodukten, somit auch nicht die allergrösste Menge. Klar, wenn man 
nun z.b. 1 Million Endgeräte über einige Jahre baut steigt die 
Kollisionsgefahr.

Zusätzlich kommt bei mir noch dazu, das pro "Anlage" nur 500-1000 Geräte 
verbaut sind. Zwei identische Nummern wären solange Egal, solange sie 
nicht in der gleichen Anlage im Einsatz sind, da Sie ja "nichts von 
einander Wissen"


Die Anforderung ist folgende:

Eine Unique 32bit ID zum einfügen von datensätzen in eine Datenbank, ist 
die ID gleich wie ein bestehnder Eintrag, soll statt "Insert" nur ein 
"Update" passieren.

Es besteht keine Notwendigkeit von der generierten ID irgendwelche 
Rückschlüsse auf die tatsächliche ID zu machen.

Früher wurde sowas mit "Silicon Serial Number" gemacht. Das würde ich 
mir aber gern sparen. Bei einer anderen Lösung wurde jeweils das EEPROM 
eines Mikrocontrollers beim Laden der Firmware mit einem aktuellen 
Zeitstempel bebrannt. Da der STM32L433 aber kein EEPROM hat, geht das 
hier nicht.

von Samuel C. (neoexacun)


Lesenswert?

Wenn es um ganze Baugruppen geht, wäre eventuell der Einsatz eines 
externen ICs passender. Mit dem könntes du garantieren, dass es keine 
Kollisionen gibt.

von chris (Gast)


Lesenswert?

Wenn es darum geht, wandel die 16bit bcd in 8bit signed int um. WAF ist 
1-25,
da reichen dann 5 bits, bleiben 11 bits frei für die LOT.
Beispiel:

uint32_t make_uid() {
#define HASH_MULTIPLIER  36 // can be 1 too for intel type checksum
uint8_t i,j; uint16_t w; uint32_t res;
w=((uint16_t*)uniq_id_1)[0]; j=w; if(w&0x8000) j|=0x80; else j&=~0x80;
i=j; // X and Y Position, int8_t format. i==X, j==Y;
w=((uint16_t*)uniq_id_1)[1]; j=w; if(w&0x8000) j|=0x80; else j&=~0x80;
res=i<<24|j<<16; w=j=*uniq_id_2; res|=j<<11; // store X,Y,WAF
// build LOT id, start with WAF id, then xor all bytes, then hash it.
for(i=1;i<4;i++) { j=*uniq_id_2>>(i<<3);  w^=j; }
for(i=0;i<4;i++) { j=*uniq_id_3>>(i<<3);  w^=j; }
for(i=1;i<4;i++) { j=*uniq_id_2>>(i<<3);  w*=HASH_MULTIPLIER; W+=j; }
for(i=0;i<4;i++) { j=*uniq_id_3>>(i<<3);  w*=HASH_MULTIPLIER; W+=j; }
w&=0x7ff; res|=w; return res; // FORMAT MSB-LSB: 
X(8)Y(8)WAF(5)LOT_HASH(11);
}

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.