Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller Klausur Aufgabe Speichertest


von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Hallo ich schreibe eine Klausur über Mikrocontroller,
ich habe viel gelernt allerdings bin ich mir mit der Aufgaben lsg. von 
mir so unsicher bzw. denke das es Falsch ist wollte mal lieb bitte 
drüber zu schauen.
Vielen dank euch allen.

Aufgabe 2: Speichertest
Es soll ein Programm zum Testen des eingebauten Speichers eines 
Mikrocontrollers
geschrieben werden.
Wenn ein Test versagt, soll der Returnwert die Adresse der fehlerhaften 
Zelle sein,
sonst soll 0x00 zurückgegeben werden.
„Single-Cell- Test“:
Das Programm hat die Aufgabe, folgende Tests mit jeder 32-bit 
Speicherzelle eines
vorgegebenen Bereichs durchzuführen:
1) 0xa5a5a5a5 schreiben und verifizieren, dass die Zelle diesen Wert 
enthält.
2) 0x00 schreiben und verifizieren, dass die Zelle diesen Wert nun 
enthält.
Codieren Sie die Funktion uint32_t * single_c_t( uint32_t * begin, 
uint32_t * end)
1
C-Code
2
//Meine Lösung (kurzer Code hoffe ist noch ok)
3
uint32_t * single_c_t( uint32_t * begin, uint32_t * end){
4
delta=*end-*begin;                    //Länge des Speichers 
5
for(int i=0;i<=delta;i++){
6
    *begin=0x5a5a5a5a;               //Speichern des Wertes 0x5a5a5a5a
7
    if(*begin!=0xa5a5a5a5a)          //Prüfen Wert gespeichert?
8
      return(&begin);                //Wenn nicht Adresse zurückgeben
9
    else
10
      *begin=0x00;                   //0x00 Speichern
11
    if(*begin!=0x00)                 //Prüfen Wert gespeichert?
12
      return(&begin);                //Wenn nicht Adresse zurückgeben
13
    else
14
     *begin++;                       //nächste Adresse also um 1 erhöhen
15
}
16
     return (0x00);
17
}

von Bimbo. (Gast)


Lesenswert?

Mal wieder extrem weltfremd. Wer testet schon EEPROM, Flash oder RAM auf 
Fehler?

von Εrnst B. (ernst)


Lesenswert?

du berechnest zwar "delta", beschreibst aber immer dieselbe 
speicherzelle "*begin".

-> mach eher sowas:
1
  for (uint32_t * lauf = begin; lauf != ende ; lauf++) {
2
     *lauf=0x5a5a5a51;
3
     if (*lauf != 0x5a5a5a51) return lauf;
4
  }
5
...

Richtig testen tut das aber nicht, der Compiler kann das wegoptimieren.
"volatile" auf "lauf" kann helfen.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Bimbo. schrieb:
> Mal wieder extrem weltfremd. Wer testet schon EEPROM, Flash oder RAM auf
> Fehler?

Ka ist ne Klausurfrage! Was hälst du von meiner LSG?

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Εrnst B. schrieb:
> du berechnest zwar "delta", beschreibst aber immer dieselbe
> speicherzelle "*begin".
>
> -> mach eher sowas:
>
1
>   for (uint32_t * lauf = begin; lauf != ende ; lauf++) {
2
>      *lauf=0x5a5a5a51;
3
>      if (*lauf != 0x5a5a5a51) return lauf;
4
>   }
5
> ...
6
>
>
> Richtig testen tut das aber nicht, der Compiler kann das wegoptimieren.
> "volatile" auf "lauf" kann helfen.

 Hallo vielen Dank für die hilfe.
1
*begin++; //erhöht doch auf die nächste Zelle oder nicht?

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:
> Ka ist ne Klausurfrage! Was hälst du von meiner LSG?

was berechnet
1
delta=*end-*begin;

Oder anders ausgedrückt: welchen wert hat "*begin"?

Henrik G. schrieb:
> Hallo vielen Dank für die hilfe.*begin++; //erhöht doch auf die nächste
> Zelle oder nicht?

ja, hab ich erst später gesehen, dein Code ist so ganz ohne Einrückungen 
schwer lesbar.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Εrnst B. schrieb:
> Oder anders ausgedrückt: welchen wert hat "*begin"?

"*begin" enthält die Adresse der Speicherzelle die Beschrieben werden 
soll.

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:
> "*begin" enthält die Adresse der Speicherzelle die Beschrieben werden
> soll.

Nö. "begin" ist die Adresse. "*begin" ist der Speicherinhalt an der 
Stelle, und den willst du nicht wirklich zum Berechnen hernehmen.

Wenn z.B. der ganze Speicher vorher voll mit 0x00 ist, dann ist *begin 
== 0x00 und *ende == 0x00, und damit delta=0, egal welcher Test-Bereich 
angegeben wurde.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Εrnst B. schrieb:
> Henrik G. schrieb:
>> "*begin" enthält die Adresse der Speicherzelle die Beschrieben werden
>> soll.
>
> Nö. "begin" ist die Adresse. "*begin" ist der Speicherinhalt an der
> Stelle, und den willst du nicht wirklich zum Berechnen hernehmen.
>
> Wenn z.B. der ganze Speicher vorher voll mit 0x00 ist, dann ist *begin
> == 0x00 und *ende == 0x00, und damit delta=0, egal welcher Test-Bereich
> angegeben wurde.

Kapiert klar es muss delta=&end-&begin;

von deristuntendurch (Gast)


Lesenswert?

Wenn dann so:

//Meine Lösung (kurzer Code hoffe ist noch ok)
uint32_t * single_c_t( uint32_t * begin, uint32_t * end){
delta=(end-begin)/sizeof(uint32_t);                    //Länge des 
Speichers
for(int i=0;i<=delta;i++){
*begin=0x5a5a5a5a;                    //Speichern des Wertes 0x5a5a5a5a
if(*begin!=0xa5a5a5a5a)               //Prüfen Wert gespeichert?
return begin;                       //Wenn nicht Adresse zurückgeben
else
*begin=0x00;                          //0x00 Speichern
if(*begin!=0x00)                      //Prüfen Wert gespeichert?
return begin;                       //Wenn nicht Adresse zurückgeben
else
begin++;                     //nächste Adresse also um 
sizeof(uint32_t)erhöhen
}
return 0;
}

Aber du hast Pointer überhaupt nicht verstanden. Dein Code war voller 
Fehler.
Die vorgeschlagene Lösung ist aber wesentlich besser.

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:

>
> Kapiert klar es muss delta=&end-&begin;

auch nicht, &begin ist die Stelle, an der die "begin" Variable selber 
gespeichert ist.

Ganz einfach
1
delta = end - begin;
ohne irgendwelche *&!#$%§.

von Markus M. (adrock)


Lesenswert?

So ganz stimmt das nicht:
1
return(&begin);                       //Wenn nicht Adresse zurückgeben

begin (ohne irgendwas davor) ist bereits die Adresse. Es wurde ja in 
der Funktionsdeklaration bereits als Zeiger festgelegt.

Somit gibt "begin" immer die Adresse zurück, auf die begin zeigt.
*begin dagegen gibt den Inhalt der Speicherzelle zurück.
1
*begin++;

Der Stern ist hier Überflüssig. Du willst ja mit dem Inhalt des 
Speichers an der Adresse von begin nichts tun. Ein
1
begin++;

reicht aus. Der Stern wäre nur bei einem solchen Konstrukt sinnvoll:
1
value = *begin++;

Das würde den Inhalt vom Speicher an der Adresse auf die begin zeigt in 
value schreiben und danach begin um eins (bzw. 4 bei uint32) erhöhen.

Die Lösung mit for() ist eleganter und schneller zugleich.

von Εrnst B. (ernst)


Lesenswert?

Das stimmt übrigens nicht:

deristuntendurch schrieb:
> delta=(end-begin)/sizeof(uint32_t);

da end und begin schon uint32_t Pointer sind, ist die Differenz davon 
die Anzahl der "uint32_t" zwischen ihnen.
Um genau das zu Umgehen (Pointer-Arithmetik ist schwer für Anfänger) hab 
ich oben vorgeschlagen:

Εrnst B. schrieb:
> for (uint32_t * lauf = begin; lauf != ende ; lauf++) {

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Markus M. schrieb:
> Das würde den Inhalt vom Speicher an der Adresse auf die begin zeigt in
> value schreiben und danach begin um eins (bzw. 4 bei uint32) erhöhen.

Wie erhöhe ich den Speicher um 1 nicht um 4?

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Εrnst B. schrieb:
> ich oben vorgeschlagen:
>
> Εrnst B. schrieb:
>> for (uint32_t * lauf = begin; lauf != ende ; lauf++) {

Würde die schleife nicht bei "ende-1" abbrechen da lauf nicht "ende" 
sein darf?

von Salamihäcksler (Gast)


Lesenswert?

> Es soll ein Programm zum Testen des eingebauten Speichers eines
Mikrocontrollers

Harvard said: 'Forget ist'; v. Neumann replied: ' don't crash on me!'

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:
> Wie erhöhe ich den Speicher um 1 nicht um 4?

indem du einen Pointer vom Typ "uint8_t *" verwendest.

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:
> Würde die schleife nicht bei "ende-1" abbrechen da lauf nicht "ende"
> sein darf?

Ja. Ist übliche Konvention, dass der "ende" Pointer nach den 
Speicherbereich zeigt, deshalb habe ich das ohne groß Nachzudenken auch 
so getippt.

Ob das mit deiner Aufgabenstellung matched, habe ich nicht geprüft.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Εrnst B. schrieb:
> indem du einen Pointer vom Typ "uint8_t *" verwendest.

kann nicht auch vl das so lösen
1
uint8_t *umeinserhoehen=0x01
2
//Meine Lösung (kurzer Code hoffe ist noch ok)
3
uint32_t * single_c_t( uint32_t * begin, uint32_t * end){
4
delta=(end-begin)/sizeof(uint32_t);                    //Länge des 
5
Speichers
6
for(int i=0;i<=delta;i++){
7
*begin=0x5a5a5a5a;                    //Speichern des Wertes 0x5a5a5a5a
8
if(*begin!=0xa5a5a5a5a)               //Prüfen Wert gespeichert?
9
return begin;                       //Wenn nicht Adresse zurückgeben
10
else
11
*begin=0x00;                          //0x00 Speichern
12
if(*begin!=0x00)                      //Prüfen Wert gespeichert?
13
return begin;                       //Wenn nicht Adresse zurückgeben
14
else
15
begin+=uint8_t umeinserhoehen;                     //nächste Adresse also um 
16
sizeof(uint32_t)erhöhen
17
}
18
return 0;
19
}

von Gerald K. (geku)


Lesenswert?

Ich würde zunächst den freien Speicher mit einem Pseudozufallsmuster 
füllen, dann dann verifieren. Das gleiche nochmals mit invertiertem 
Muster. Damit können defekte Speicherzellen (was eher unwahrscheinlich 
ist) und Kurzschlüsse sowie Unterbrechungen von Speicheranschlüsse 
erkannt werden.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Gerald K. schrieb:
> Ich würde zunächst den freien Speicher mit einem Pseudozufallsmuster
> füllen, dann dann verifieren. Das gleiche nochmals mit invertiertem
> Muster. Damit können defekte Speicherzellen (was eher unwahrscheinlich
> ist) und Kurzschlüsse sowie Unterbrechungen von Speicheranschlüsse
> erkannt werden.

Hallo Gerald,
ich danke dir für die Antwort allerdings ist das so nicht in der Aufgabe 
verlangt.
Kannst du mir vl anderst helfen wie bekomme ich den uint32_t Pointer um 
eine Speicherzelle erhöht?
Kann ich diesen einfach zu einen uint8_t Pointer umwandeln?

von Εrnst B. (ernst)


Lesenswert?

Henrik G. schrieb:
> kann nicht auch vl das so lösen

Was willst du da lösen?
Wenn du Pointer auf einen 32-Bit Wert erhöhst (++), wandert der Pointer 
um 32 Bit weiter. Bei einem Pointer auf uint8_t, uint16_t, uint64_t etc 
genauso analog. Vollautomatisch.

Also:
Du brauchst kein Sizeof-Gewurschtel, das kann der Compiler alles selber. 
Pfusch ihm da nicht rein, er kann das nämlich nicht nur selbst, sondern 
auch besser als du mit deinem aktuellen Kenntnisstand.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Also ich würde das jetzt so lösen und danke euch allen für die Hilfe. 
Habe viel gelernt auch das ich mir Pointer nochmal genauer anschauen 
muss.
1
uint32_t * single_c_t( uint32_t * begin, uint32_t * end){
2
                         
3
for (uint32_t * lauf = begin; lauf <= ende ; lauf++){
4
    *begin=0x5a5a5a5a;                    //Speichern des Wertes 0x5a5a5a5a
5
    if(*begin!=0xa5a5a5a5a)               //Prüfen Wert gespeichert?
6
       return begin;                       //Wenn nicht Adresse zurückgeben
7
    else
8
       *begin=0x00;                          //0x00 Speichern
9
    if(*begin!=0x00)                      //Prüfen Wert gespeichert?
10
       return begin;                       //Wenn nicht Adresse zurückgeben
11
      else                
12
}
13
return 0x00;
14
}

von Εrnst B. (ernst)


Lesenswert?

Etwas Offtopic, aber, um

Εrnst B. schrieb:
> Richtig testen tut das aber nicht, der Compiler kann das wegoptimieren.

zu demonstrieren:
1
#include <stdint.h>
2
3
uint32_t * single_c_t( uint32_t * begin,  uint32_t * end) {
4
    for (uint32_t * lauf=begin; lauf<=end; lauf++) { 
5
        *lauf=0xa5a5a5a5;
6
        if (*lauf != 0xa5a5a5a5) return lauf;
7
        *lauf=0x00;
8
        if (*lauf != 0x00) return lauf;
9
    }
10
    return 0;
11
}

macht der GCC mit Optimierung zu:
1
single_c_t:
2
.LFB0:
3
        .cfi_startproc
4
        endbr64
5
.L2:
6
        cmpq    %rsi, %rdi
7
        ja      .L5
8
        movl    $0, (%rdi)
9
        addq    $4, %rdi
10
        jmp     .L2
11
.L5:
12
        xorl    %eax, %eax
13
        ret
14
        .cfi_endproc

Also Befüllen des Speichers mit 0 und return 0. Keinerlei Check.

erst mit einem
for (volatile uint32_t * lauf=begin;...

wird was vernünftiges draus:
1
single_c_t:
2
.LFB0:
3
        .cfi_startproc
4
        endbr64
5
        movq    %rdi, %rax
6
.L2:
7
        cmpq    %rsi, %rax
8
        ja      .L6
9
        movl    $-1515870811, (%rax)
10
        movl    (%rax), %edx
11
        cmpl    $-1515870811, %edx
12
        jne     .L1
13
        movl    $0, (%rax)
14
        movl    (%rax), %edx
15
        testl   %edx, %edx
16
        jne     .L1
17
        addq    $4, %rax
18
        jmp     .L2
19
.L6:
20
        xorl    %eax, %eax
21
.L1:
22
        ret
23
        .cfi_endproc

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Stimmt! Hast du ja geschrieben vielen dank!

von Gerald K. (geku)


Lesenswert?

Henrik G. schrieb:
> Kannst du mir vl anderst helfen wie bekomme ich den uint32_t Pointer um
> eine Speicherzelle erhöht?
1
uint32_t px;   // Zeiger deklarieren
2
3
// SPEICHER FÜLLEN
4
5
px = ANFANGSADRESSE; // Zeiger intalisieren
6
7
while (px < ENDADRESSE) {
8
    *px++ = 0xa5a5a5a5;  // Speicher initalisieren (1. 32 Bit bzw. 1. 4 Bytes)
9
    *px++ = 0x5a5a5a5a;  // Speicher initalisieren (2. 32 Bit bzw. 2. 4 Bytes)
10
};
11
12
// SPEICHER TESTEN
13
px = ANFANGSADRESSE; // Zeiger intalisieren
14
15
while (px < ENDADRESSE) {
16
    if (*px++ != 0xa5a5a5a5) {  // Speicher testen (1. 32 Bit bzw. 1. 4 Bytes)
17
        printf("error address:  0x%08×/r/n",--px);
18
        break;
19
    }
20
    if (*px++ != 0x5a5a5a5a) {  // Speicher testen (2. 32 Bit bzw. 2. 4 Bytes)
21
        printf("error address: 0x%08x/r/n",--px);
22
        break;
23
     } 
24
};

Der Algorithmus erkennt viele Fehler nicht!

Anmerkung :

 Zeigerarithmetik mit Zeiger vom Typ uint32_t  verändern den Zeiger um 4

px++     0x0 => 0x4
px--        0x8 => 0x4

Zeigerarithmetik mit Zeiger vom Typ uint8_t  verändern den Zeiger um 1

(uint8_t)px++     0x0 => 0x1
(uint8_t)px--       0x5 => 0x4

> Kann ich diesen einfach zu einen uint8_t
> Pointer umwandeln?

Man kann einen CAST durchführen :

(uint8_t)px

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Henrik G. schrieb:
>
1
> uint32_t * single_c_t( uint32_t * begin, uint32_t * end){
2
> 
3
> for (uint32_t * lauf = begin; lauf <= ende ; lauf++){
4
>     *begin=0x5a5a5a5a;                    //Speichern des Wertes 
5
> 0x5a5a5a5a
6
>     if(*begin!=0xa5a5a5a5a)               //Prüfen Wert gespeichert?
7
>        return begin;                       //Wenn nicht Adresse 
8
> zurückgeben
9
>     else
10
>        *begin=0x00;                          //0x00 Speichern
11
>     if(*begin!=0x00)                      //Prüfen Wert gespeichert?
12
>        return begin;                       //Wenn nicht Adresse 
13
> zurückgeben
14
>       else
15
> }
16
> return 0x00;
17
> }
18
>

Das hast du so durch den Compiler bekommen? Wow ...
Und funktioniert hat es auch noch? Doppelt Wow ...

Reden wir Tacheles. Was da steht ist schlampig und du hast nicht 
wirklich verstanden was du da machst. Von den Verstößen gegen seit 
Jahrzehnte beim C-Programmieren üblichen Konventionen, zur Verringerung 
von Flüchtigkeitsfehlern, gar nicht zu reden.

Was ich da verzeihen würde wäre die fehlende Verwendung von UINT32_C. 
Das wissen die meisten Helden hier auch nicht.

von Gerald K. (geku)


Lesenswert?

Besser Fehlererkennung :
1
 *px;   // Zeiger deklarieren ( *Achtung* : Stern hat bei meinem vorangegangen Beispiel gefehlt)
2
uint32_t  i
3
4
5
// SPEICHER FÜLLEN
6
7
px = ANFANGSADRESSE; // Zeiger intalisieren 
8
i = 0x5a5a5a5a;
9
10
while (px < ENDADRESSE) {
11
    *px++ = i =  crcr32(i,i,4);  // Speicher initalisieren
12
};
13
14
// SPEICHER TESTEN
15
px = ANFANGSADRESSE; // Zeiger intalisieren
16
i = 0x5a5a5a5a;
17
18
while (px < ENDADRESSE) {
19
    if (*px++ != (i = crc32(i,i,4)) {  // Speicher testen
20
        printf("error address:  0x%08×/r/n",--px);
21
        break;
22
     } 
23
};

zweiter Durchgang mit invertiertem Muster:
1
 *px;   // Zeiger deklarieren ( *Achtung* : Stern hat bei meinem vorangegangen Beispiel gefehlt)
2
uint32_t  i
3
4
5
// SPEICHER FÜLLEN
6
7
px = ANFANGSADRESSE; // Zeiger intalisieren 
8
i = 0x5a5a5a5a;
9
10
while (px < ENDADRESSE) {
11
    i =  crcr32(i,i,4);  // Speicher initalisieren
12
    *px++   = ~i;
13
};
14
15
// SPEICHER TESTEN
16
px = ANFANGSADRESSE; // Zeiger intalisieren
17
i = 0x5a5a5a5a;
18
19
while (px < ENDADRESSE) {
20
    i =crc32(i,i,4);
21
    if (*px++ != ~i) {  // Speicher testen
22
        printf("error address:  0x%08×/r/n",--px);
23
        break;
24
     } 
25
};

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Gerald K. schrieb:

> Anmerkung :
>
>  Zeigerarithmetik mit Zeiger vom Typ uint32_t  verändern den Zeiger um 4
>
> px++     0x0 => 0x4
> px--        0x8 => 0x4
>
> Zeigerarithmetik mit Zeiger vom Typ uint8_t  verändern den Zeiger um 1
>
> (uint8_t)px++     0x0 => 0x1
> (uint8_t)px--       0x5 => 0x4
>
>> Kann ich diesen einfach zu einen uint8_t
>> Pointer umwandeln?
>
> Man kann einen CAST durchführen :
>
> (uint8_t)px

Hallo Vielen dank für deine Ausführliche Antwort.
Ich habe, glaube ich jetzt alles verstanden bitte korrigiere mich.
Also ich habe 32 bit Register wenn ich einen Pointer habe mit uint32_t 
dann beschreibe ich alle 32 bit im Register mit *ptr. Erhöhe ich diesen 
Pointer um 1 (ptr ohne stern) dann wandert dieser logischer Weiße 32 bit 
höher (in nächste Register)damit ich die letzten 32 bit nicht 
überschreibe. Wenn ich Uint16_t habe beschreibe ich nur die ersten 16 
bits und bei uint8_t die ersten 8 bit. Wenn ich im Register den Wert der 
im Register steht um ein erhöhen mag kann ich den Pointer casten also 
(uint8_t)ptr um dann den wert im Register mit *ptr++ um einzuerhöhen.

Welche Fehler meinst du erkennt der Algo nicht, also wenn es solche 
Fehler sind wie begin>end oder sowas glaube ich nicht das er das will 
aber fragen werde ich in der Klausur sicherlich.

von Henrik G. (Firma: Student) (kaltesblondes)


Lesenswert?

Hannes J. schrieb:
> Reden wir Tacheles. Was da steht ist schlampig und du hast nicht
> wirklich verstanden was du da machst. Von den Verstößen gegen seit
> Jahrzehnte beim C-Programmieren üblichen Konventionen, zur Verringerung
> von Flüchtigkeitsfehlern, gar nicht zu reden.
>
> Was ich da verzeihen würde wäre die fehlende Verwendung von UINT32_C.
> Das wissen die meisten Helden hier auch nicht.

Hallo ich danke dir für die Kritik. Wie du sicherlich bemerkt hast bin 
ich in einem lernprozess und versuche mich zuverbessern und dazu 
zulernen. Das Bibilotheken fehlen ist ganz klar vl ein fehler aber 
sicherlich nicht für eine Funktion bzw Methode relevant diese sollten im 
Hauptprogramm stehen. Mich interresieren die Konventionen bitte 
erläutere mir dies damit ich das in zukumft beachten kann.
Vielen dank im voraus!

von Gerald K. (geku)


Lesenswert?

Henrik G. schrieb:
> Welche Fehler meinst du erkennt der Algo nicht, also wenn es solche
> Fehler sind wie begin>end oder sowas glaube ich nicht das er das will
> aber fragen werde ich in der Klausur sicherlich.

Einfaches Beispiel :
1
Adresse                Daten 
2
          Bit: 3210
3
0x00    0b0000    0xa5a5a5a
4
0x04    0b0100    0x5a5a5a5
5
0x08    0b1000    0xa5a5a5a
6
0x0c    0b1100    0x5a5a5a5

Wenn das Adressbit 3 einen Kurzschluss gegen GND hat, dann wird statt 
Adresse 0x08 bzw.  0x0c auf die Adresse 0x00 bzw  0x04 geschrieben und 
beim "Verify" gelesen.  Nachdem 0x08 und 0x00 bzw. 0x0c und 0x04 den 
gleichen Inhalt haben bleibt dieser Kurzschluss unentdeckt
Es gibt noch viele andere solche Konstellationen von Fehlern, die 
unentdeckt bleiben.

Fazit : ein Prüfmuster darf keine Regelmässigkeit aufweisen.
Ein gutes Prüfmuster wäre die Zahl Pi oder auch Pseudozufallszahlen.

von Thomas (kosmos)


Lesenswert?

Auf jeden Fall würde ich noch vermerken das man jede Zelle sowohl auf 1 
als auch auf 0 testen sollte. Mit dem geforderte Test überprüft man 
nicht alle Zellen auf 1

Also neben deinen a5a5a5a5
10100101101001011010010110100101
und 0 Muster
00000000000000000000000000000000
auch auf ff ff ff ff
11111111111111111111111111111111
testen sonst bleibt 50% der Zellen ungetestet.

Wobei man a5a5a5a5 dann auch komplett weglassen könnte.

von Gerald K. (geku)


Lesenswert?

Thomas O. schrieb:
> Auf jeden Fall würde ich noch vermerken das man jede Zelle sowohl auf 1
> als auch auf 0 testen sollte. Mit dem geforderte Test überprüft man
> nicht alle Zellen auf 1

mit abwechselnd 0x5a5a5a5a und 0xa5a5a5a5 werden zumindest Kurzschlüsse 
und Unterbrechungen benachbarter Bits (Leitungen?) erkannt.

Bei 0x00000000 bzw. 0x11111111 werden diese nicht erkannt
Aufwendige Speichertest schieben einzelne Bits durch den Speicher und 
testen immer alle anderen Speicherzellen. Das ist sehr sehr 
zeitaufwendig.

von Juhu (Gast)


Lesenswert?

Thomas O. schrieb:
> Auf jeden Fall würde ich noch vermerken das man jede Zelle sowohl auf 1
> als auch auf 0 testen sollte. Mit dem geforderte Test überprüft man
> nicht alle Zellen auf 1

Immer noch nicht gemerkt das es für diese Klausuraufgabe VOLLKOMMEN 
UNINTERESSANT ist ob dieser Speicher jetzt vollständig geprüft wird.

Der Sinn von solchen Aufgaben ist es das der Schüler eine Lösung 
präsentiert die der Problemstellung entspricht. Ansonsten würde da 
stehen "Diskutieren Sie Speichertest...Vorteile...Nachteile...bla 
bla...".

Darum geht es aber nicht Ihr "Experten".

von Gerald K. (geku)


Lesenswert?

Henrik G. schrieb:
> for(int i=0;i<=delta;i++){
>     *begin=0x5a5a5a5a;               //Speichern des Wertes 0x5a5a5a5a
>     if(*begin!=0xa5a5a5a5a)          //Prüfen Wert gespeichert?
>       return(&begin);                //Wenn nicht Adresse zurückgeben

Dieser Test bringt gar nichts! Funtioniert auch mit einem 32 Bit Latch. 
Vielleicht sigar nur mit 32 Kondensatoren an den Ports. Dazu braucht man 
kein "Experte" zu sein!

von Εrnst B. (ernst)


Lesenswert?

Gerald K. schrieb:
> Dieser Test bringt gar nichts

Darum geht es doch auch garnicht. Lernziele, die in der Klausur 
überprüft werden sollten waren vermutlich:
- Schleifen
- Bitbreiten verschiedener Integer-Datentypen
- Speicherzugriff über Pointer
- Pointerarithmetik
- Evtl: "volatile".

Das ganze halt in eine fiktive Aufgabe verpackt, um einen Anschein von 
Realitätsbezug herzustellen.
Insofern: Schöne Aufgabe, begrenzter Umfang, lässt sich auch mit 
Papier-und-Bleistift in der Klausur erledigen.
Das niemand so einen Test real und produktiv einsetzen würde, ist dabei 
doch Nebensache, und war dem Aufgabensteller auch ganz bestimmt klar.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Εrnst B. schrieb:
> Insofern: Schöne Aufgabe,

Nee, schoen find' ich die ganz und gar nicht.
Nicht wegen den Testmethoden, sondern wegen des Rueckgabewerts. Ich kann 
nicht in einer Funktion entweder Pointer zurueckgeben oder numerische 
Werte (hier 0x00). Sowas ist in einer Aufgabenstellung aeusserst 
unschoen.

Gruss
WK

Beitrag #6341605 wurde von einem Moderator gelöscht.
von Εrnst B. (ernst)


Lesenswert?

Dergute W. schrieb:
> sondern wegen des Rueckgabewerts.

0 ist NULL und ein üblicher Rückgabewert bei Funktionen, die einen 
Pointer zurückgeben sollen. Und ja, 0 oder 0x00 auf uint32_t* zu casten 
ist vom Standard abgedeckt.

Ok, die Rückgabewert-Logik ist jetzt andersherum als bei "malloc", mit 
NULL=>OK, !NULL=>Fehler, aber passt z.B. auf einige der 
string.h-Funktionen.

Statt

Dergute W. schrieb:
> aeusserst unschoen

Würde ich also eher was wie "Hier könnte man, wenn man unbedingt was zum 
Bemängeln braucht, ein paar Stil-Punkte abziehen" anmerken.

Denn wirklich "unschön" ist das nicht, erst recht nicht "äußerst 
unschön".

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Und genau damit:

Εrnst B. schrieb:
> 0 ist NULL

hab' ich ganz erhebliche Probleme bei einer Aufgabenstellung. Klar kann 
ich allen moeglichen und unmoeglichen Krempel casten. Und wenns nicht 
ganz obskur ist, macht's vielleicht der Compiler auch einfach so 
automatisch.

Bleibt aber trotzdem schlechter Stil, wenn man nicht unterscheidet 
zwischen Pointer und numerischer Konstante. Und grad' wenn man eine 
Sprache beigebracht bekommen hat und soll dann so eine unsauber 
gestellte Aufgabe loesen, wie will man's dann richtig lernen?

Ein guter Fahrlehrer wird auch kaum in's Auto einsteigen, Fluppe 
anzuenden und andere Verkehrsteilnehmer mit Schimpfworten bedenken. 
Obwohl man auch so Auto fahren kann.
Und dann bin ich mir garnicht mal ganz sicher, ob's nicht in irgendeiner 
obskuren CPU sein koennte, dass (int)NULL eben nicht 0 ist...

Gruss
WK

von Jemand (Gast)


Lesenswert?

Εrnst B. schrieb:
> 0 ist NULL und ein üblicher Rückgabewert bei Funktionen, die einen
> Pointer zurückgeben sollen. Und ja, 0 oder 0x00 auf uint32_t* zu casten
> ist vom Standard abgedeckt.

Eine integer constant expression mit Wert 0 cast zu einem Pointer 
ist garantiert NULL, ein beliebiger Integer mit Wert 0 nicht. Ein 
cast kommt da aber nicht mal vor, da ist nur eine implizite 
Umwandlung. Der Code ist strenggenommen fehlerhaft. Glücklicherweise ist 
NULL aber meistens tatsächlich 0, damit seit ihr Pfuscher weniger 
gefährlich.

von Εrnst B. (ernst)


Lesenswert?

Dergute W. schrieb:
> Bleibt aber trotzdem schlechter Stil

Sahen K&R anders.

Jemand schrieb:
> da ist nur eine implizite Umwandlung.

Für die gilt das auch.

>> In appropriate contexts in source code, [...] a null pointer constant can
>> be written as 0, with or without explicit casting to a pointer type, or
>> as the NULL macro defined by several standard headers. In conditional
>> contexts, null pointer values evaluate to false, while all other pointer
>> values evaluate to true.

Insofern: "return 0;" ist voll OK.

Wenn ihr wirklich was zum rummäkeln an der Aufgabe sucht, fangt bei der 
Paramterübergabe an. Da ist nämlich nicht definiert ob "end" in den 
Testbereich includiert oder exkludiert ist, und das ist ein echtes 
Problem und nicht nur ein an den Haaren herbeigezogenes 
Wischiwaschi-"Schlechter Stil"-Argument.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Εrnst B. schrieb:
> Sahen K&R anders.

Nee, seh' ich nicht so:
>>> In appropriate contexts in source code,

Es gibt sicher z.b. Berufskraftfahrer, die zur Stressbewaeltigung beim 
Fahren rauchen und andere Verkehrsteilnehmer beschimpfen. Trotzdem 
erwarte ich von einem guten Fahrlehrer kein solches Verhalten.
Und hier finde ich den context (Klausuraufgabenstellung) eben nicht 
appropriate, um NULL und 0 zu verwursten.

Wenns alles wurscht und eh immer das selbe ist, warum gibt es denn die 
Bezeichnung NULL fuer einen Nullpointer. Die waere doch dann voellig 
ueberfluessig...

Gruss
WK

von Stefan F. (Gast)


Lesenswert?

Εrnst B. schrieb:
>> Bleibt aber trotzdem schlechter Stil
> Sahen K&R anders.

Deren Maßstäbe entsprechen nicht mehr dem aktuellen Stand. Die 
Grundlagen bleiben, Details ändern sich.

Selbst der Herr Stroustrup (C++) hat in seinen neueren Büchern darauf 
hingewiesen, dass er einigen seiner alten Empfehlungen heute nicht mehr 
zustimmen würde. Er schreibt sogar, dass er "seine" Programmiersprache 
heute anders gestalten würde, wenn er sie heute neu erfinde würde.

Ist das nicht vollkommen normal? Die Firma Sun hatte sich mit Java große 
Mühe gegeben, eine Programmiersprache zu schaffen, die mit alten 
Fallstricken und Problem aufräumt. Sie haben ihr eigenes Ziel weit 
verfehlt. Nur wenige Fallstricke sind wirklich weg, dafür haben wir neue 
bekommen.

von Roland E. (roland0815)


Lesenswert?

Bimbo. schrieb:
> Mal wieder extrem weltfremd. Wer testet schon EEPROM, Flash oder RAM auf
> Fehler?

Jeder, der mit sicherheitskritischen programmierbaren Systemen der 
Klasse C zu tun hat. Bei jedem Start und auch zur Laufzeit. Nicht ganz 
so plump wie der Test oben, aber es geht hier ja ums Prinzip und den 
Lösungsansatz. Flash und (E)Eprom löscht man zB nicht beim Testen. Da 
gibt es andere Verfahren.

Zur Abwechslung ist das tatsächlich mal eine Aufgabe mit Praxisbezug.

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.