Forum: Compiler & IDEs Debugging mit MPLAB X und XC-8


von Sebastian (basti73)


Lesenswert?

Hallo zusammen,

ich bastle an einer Funktion herum, die mir zwei uint32_t[4] vergleichen 
soll. Dieser Funktion übergebe ich die Pointer auf die Arrays, während 
des Vergleichs wird beim Durchsteppen aber an irgendeiner Stelle die 
Referenz zerstört, danach schlägt der Vergleich fehl.
Leider habe ich außer dem Debugging keine Möglichkeit nachzuvollziehen, 
was das Programm macht (außer, dass ich weiß, dass es nicht das tut, was 
ich möchte).
Beim Aufruf der Funktion CompareColors werden die richtigen Adressen 
übergeben (lt. Debugger liegt background auf 0x0110 und measurement auf 
0x0120), mit dem Eintritt in die for-Schleife zeigt er beim ersten 
Vergleich, dass die Adressen entweder "irgendwas" enthalten, hier wurde 
immer wieder 0x0940 gezeigt, oder der Debugger sagt "out of scope")

Ich habe auch versucht die Variablen als volatile zu definieren, ebenso 
habe ich versucht die Funktionsparameter als const zu definieren. In 
beiden Fällen unterscheidet sich vielleicht die Anzeige, ich habe aber 
nichts gefunden, mit dem der Vergleich sauber funktioniert. Auch ein 
Zugriff über reference[0] ändert nichts.

Umgebung:
MPLAB X IDE v6.05
XC8 v2.4
pickit4

Relevanter Code (main ist leicht gekürzt, ist aber für diesen Punkt 
nicht relevant):
1
uint32_t measurement[4] = {-1, -1, -1, -1};
2
uint32_t background[4]  = {-1, -1, -1, -1};
3
uint32_t reference[4]   = {-1, -1, -1, -1};
4
5
int main(void) {
6
    
7
    Init();
8
    
9
    MeasureColor(background);
10
    while (CompareColors(background, measurement)) {
11
        //FlipUnmatch();
12
        //_delay_ms(DELAY);
13
        MeasureColor(measurement);
14
    }
15
}
16
17
18
int CompareColors(uint32_t * reference, uint32_t * probe) {
19
    for(int i = 0;i<4;i++) {
20
        if (*reference > *probe) {
21
            if ((*reference - *probe) > COLORDELTA) {
22
                return 0;
23
            }
24
        } else {
25
            if ((*probe - *reference) > COLORDELTA) {
26
                return 0;
27
            }
28
        }
29
        reference++;
30
        probe++;
31
    }
32
    return 1;
33
}

Ausgabe build
1
make -f nbproject/Makefile-debug.mk SUBPROJECTS= .build-conf
2
make[1]: Entering directory 'C:/Projekte/private.Colorsort.X'
3
make  -f nbproject/Makefile-debug.mk dist/debug/debug/private.Colorsort.X.debug.elf
4
make[2]: Entering directory 'C:/Projekte/private.Colorsort.X'
5
"C:\Program Files\Microchip\xc8\v2.40\bin\xc8-cc.exe"  -mcpu=ATmega328P -c  -D__DEBUG=1 -g -DDEBUG  -gdwarf-2  -x c -D__ATmega328P__   -mdfp="C:/Program Files/Microchip/MPLABX/v6.05/packs/Microchip/ATmega_DFP/3.0.158/xc8"  -Wl,--gc-sections -O0 -Og -ffunction-sections -fdata-sections -fno-common -funsigned-char -funsigned-bitfields -Wall -DXPRJ_debug=debug    -gdwarf-3 -mconst-data-in-progmem -mno-const-data-in-config-mapped-progmem     -MD -MP -MF "build/debug/debug/main.o.d" -MT "build/debug/debug/main.o.d" -MT build/debug/debug/main.o -o build/debug/debug/main.o main.c 
6
"C:\Program Files\Microchip\xc8\v2.40\bin\xc8-cc.exe"  -mcpu=ATmega328P -c  -D__DEBUG=1 -g -DDEBUG  -gdwarf-2  -x c -D__ATmega328P__   -mdfp="C:/Program Files/Microchip/MPLABX/v6.05/packs/Microchip/ATmega_DFP/3.0.158/xc8"  -Wl,--gc-sections -O0 -Og -ffunction-sections -fdata-sections -fno-common -funsigned-char -funsigned-bitfields -Wall -DXPRJ_debug=debug    -gdwarf-3 -mconst-data-in-progmem -mno-const-data-in-config-mapped-progmem     -MD -MP -MF "build/debug/debug/servo.o.d" -MT "build/debug/debug/servo.o.d" -MT build/debug/debug/servo.o -o build/debug/debug/servo.o servo.c 
7
"C:\Program Files\Microchip\xc8\v2.40\bin\xc8-cc.exe"  -mcpu=ATmega328P -c  -D__DEBUG=1 -g -DDEBUG  -gdwarf-2  -x c -D__ATmega328P__   -mdfp="C:/Program Files/Microchip/MPLABX/v6.05/packs/Microchip/ATmega_DFP/3.0.158/xc8"  -Wl,--gc-sections -O0 -Og -ffunction-sections -fdata-sections -fno-common -funsigned-char -funsigned-bitfields -Wall -DXPRJ_debug=debug    -gdwarf-3 -mconst-data-in-progmem -mno-const-data-in-config-mapped-progmem     -MD -MP -MF "build/debug/debug/TCS230.o.d" -MT "build/debug/debug/TCS230.o.d" -MT build/debug/debug/TCS230.o -o build/debug/debug/TCS230.o TCS230.c 
8
"C:\Program Files\Microchip\xc8\v2.40\bin\xc8-cc.exe"  -mcpu=ATmega328P -Wl,-Map=dist/debug/debug/private.Colorsort.X.debug.map  -D__DEBUG=1  -DXPRJ_debug=debug  -Wl,--defsym=__MPLAB_BUILD=1   -mdfp="C:/Program Files/Microchip/MPLABX/v6.05/packs/Microchip/ATmega_DFP/3.0.158/xc8"   -gdwarf-2 -Wl,--gc-sections -O0 -Og -ffunction-sections -fdata-sections -fno-common -funsigned-char -funsigned-bitfields -Wall -gdwarf-3 -mconst-data-in-progmem -mno-const-data-in-config-mapped-progmem      -Wl,--memorysummary,dist/debug/debug/memoryfile.xml -o dist/debug/debug/private.Colorsort.X.debug.elf  -o dist/debug/debug/private.Colorsort.X.debug.elf  build/debug/debug/initializeChip.o build/debug/debug/main.o build/debug/debug/servo.o build/debug/debug/TCS230.o      -Wl,--start-group  -Wl,-lm -Wl,--end-group  -Wl,--defsym=__MPLAB_DEBUG=1,--defsym=__DEBUG=1
9
Info: Loading file: c:\program files\microchip\xc8\v2.40\avr\avr\bin\../lib\ldscripts/avr5.xn
10
make[2]: Leaving directory 'C:/Projekte/private.Colorsort.X'
11
make[1]: Leaving directory 'C:/Projekte/private.Colorsort.X'

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Keywords: implicit type promotion rules, int promotion!

Bedeutet bei 8-bit uC gehts Richtung int16_t,
also die Condition Operatoren casten (uint32_t) ...

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Sebastian schrieb:
> Ich habe auch versucht die Variablen als volatile zu definieren, ebenso
> habe ich versucht die Funktionsparameter als const zu definieren.

Unbegründetes trail & error Spielen!? Spätestens jetzt sollte bewusst 
werden, dass grundsätzlich was im Verständnis fehlt ...

von Sebastian (basti73)


Lesenswert?

Hallo und danke für die Antworten,

- implicit type promotion:
  Ich habe diesbezüglich gegoogelt und die Doku für XC8 sagt: "uint32_t 
Unsigned integer of exactly 32 bits
width.
unsigned long"
  Ich verstehe es so, dass xc8 diese Typen unterstützt (und lt. Doku 
sogar unsigned long long int) und dass der Compiler dafür sorgt, dass 
diese Variablen richtig verarbeitet werden. Sollte das nicht so sein, 
bin ich sehr an einer Erklärung interessiert.

- volatiles Verständnisproblem:
  Ich möchte nicht darauf eingehen, wie sinnlos der Beitrag ist. Ich 
habe geschrieben, dass das von mir erwartete Verhalten nicht gezeigt 
wurde. Damit muss ich meine Erwartungen hinterfragen und nach einigem 
erfolglosen googeln bin ich bei volatile und Compileroptimierungen 
gelandet. Natürlich ist das Trial and Error, hätte ich eine Lösung, 
würde ich hier nicht fragen.

Ich bin Anfänger in C und willig zu lernen. Da der Debugger Sachen 
macht, die ich nicht erklären kann, gibt es die Variante, dass in den 
paar von mir geposteten Zeilen etwas den Heap umschreibt oder sonst 
irgendwelche Schweinereien macht (die Init() Funktion schiebt nur 
Register für die Pin-Definition) oder der Debugger den Ablauf 
durcheinanderbringt. Beides würde ich verstehen, hätte aber gern 
verstanden, warum das so ist.

tia

Sebastian

von Frank K. (fchk)


Lesenswert?

Wie ist COLORDELTA definiert?

const uint32_t COLORDELTA=234523UL;

Das UL am Ende steht da nicht nur zum Spaß.

fchk

von Hans K. (gamp)


Lesenswert?

Hallo,
Du verwendest 32 Bit Werte in einem Array. Du möchtest im Array durch 
Inkrementieren des Pointers den nächsten Wert erreichen.
Ich weiß jetzt nicht, welchen Controller du verwendest aber evtl. musst 
du um mehrere Bytes inkrementieren um den Pointer zum nächsten 
Array-Element setzen.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Sebastian schrieb:
> Ich habe diesbezüglich gegoogelt und die Doku für XC8 sagt: "uint32_t
> Unsigned integer of exactly 32 bits width unsigned long"

... dann google nochmal und fang an nachzudenken! Welche Typen XC8 
unterstützt hat nichts mit int Promotion zu tun.

Sebastian schrieb:
> - volatiles Verständnisproblem:

... erkennbar hast du kein Verständnis vom Sinn zu const und volatile 
und zudem die Vorstellung das dritte als Erklärbär dir das abnehemen, 
dieses copy&past Verhalten verdient laute Kritik und ist leider typisch 
für die vielen Anhnungslosen unserer Zeit. Selber arbeiten? Nee warum, 
die Community macht das alles für mich ...

... und Leseverständnis auch mehr als unzureichend, weil die angebene 
Lsg. wurde erkennbar auch nicht ausprobiert.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Hans K. schrieb:
> Du verwendest 32 Bit Werte in einem Array. Du möchtest im Array durch
> Inkrementieren des Pointers den nächsten Wert erreichen.
> Ich weiß jetzt nicht, welchen Controller du verwendest aber evtl. musst
> du um mehrere Bytes inkrementieren um den Pointer zum nächsten
> Array-Element setzen.

... gehe besser was anderes spielen!
Ein Pointer ist Type und Maschinen abhängig und incrementiert 
entsprechend, also hier bei 8-bit Maschine viermal.

von Sebastian (basti73)


Lesenswert?

Hi,

wenn deine Aussagen auch ohne persönliche Angriffe gingen, könnte ich 
sogar annehmen, dass das hier ein Forum ist, in dem man bei Unklarheiten 
nachfragen kann -> man kann offensichtlich nicht alles haben. Ich habe 
von meinem Code nichts kopiert, ich wüsste noch nicht mal, woher. Bei 
der Einfachheit der Funktionen gäbe es dafür auch keinen Grund

Zur implicit type promotion:
Die Regeln der impliziten Konvertierung besagen, dass im Falle des 
Falles nach oben konvertiert wird, int zu long zu long long, bzw. von 
signed zu unsigned.
Jetzt habe ich schon unsigned long, eine Umwandlung kann das System von 
mir aus auch machen, das war niemals meine Frage, lasse mich aber gerne 
erklären, warum das relevant ist.

Meine Frage, zur nochmaligen Erklärung, war, warum der Debugger von 
MPLAB X beim Durchsteppen durch die Funktion beim Funktionseinstieg die 
jeweilige Adresse für die beiden Argumente anzeigt (und damit auch Werte 
der Speicherstelle), nach dem ersten Vergleich (bei dem gerne gecasted 
werden kann, das ist erst in zweiter Linie für meine Frage relevant) 
aber weder eine Adresse noch ein Wert angezeigt wird (der Debugger zeigt 
danach nur mehr "out of scope"). Wenn das ein systemimanentes Problem 
des Debuggers darstellt kann das natürlich so sein. Wenn der Debugger 
bekanntermaßen immer einwandfrei und anstandslos Variablen anzeigt (ich 
arbeite normalerweise mit Visual Studio und bin den Debugger dort 
gewöhnt, verstehe aber die Schwierigkeiten auf einem Mikrocontroller zu 
debuggen), habe ich, trotz keiner schreibenden Funktionen (ausgenommen 
die Zuweisung von i für die Schleife) anscheinend etwas, das die 
Speicherstelle überschreibt.

Dass volatile normalerweise nur bei etwas wie Interrupts benötigt wird, 
weiß ich, dass const in der Argumentdeklaration vor der Typzuweisung 
eigentlich die Adresse, aber nicht den Wert, konstant halten sollte (im 
Unterschied zu const vor dem Argumentnamen), weiß ich ebenfalls. Nach 
dem wir jetzt das Wettpissen hinter uns gebracht haben, könnte sich 
vielleicht jemand finden, der einem Entwickler, der normalerweise eher 
im C# und Visual Studio Umfeld arbeitet und sich erst kurz mit ATmega 
auseinandersetzt, vernünftig erklärt, warum ich sehe, was ich sehe.

tia

Sebastian

: Bearbeitet durch User
von Sebastian (basti73)


Lesenswert?

Hi,

noch ein Nachsatz:
Ich habe COLORDELTA überprüft, das UL hat gefehlt, ich habe es 
nachgetragen. Es ändert aber immer noch nichts an dem Verhalten, das ich 
beim Debuggen sehe.
Daher nochmal zur Klarstellung: Mir geht es gerade um eine Aussage über 
die Zuverlässigkeit von Debugger-Anzeigen, nicht um den direkten 
Programmablauf.

tia

Sebastian

von Erich (Gast)


Lesenswert?

Du solltest 2-3 freie Pins deines uC nutzen als "Toggle"-Melder.
Mit Scope in Echtzeit verfolgen wo das Programm hinläuft.
Das ist zuverlässiger als Debugger.

Gruss

von Sebastian (basti73)


Lesenswert?

Hallo Erich,

danke für die Info. Das mit den Toggle-Pins hatte ich schon gemacht, 
mich hat "nur" die Anzeige des Debuggers verwirrt. Seit ich weiß, was 
ich davon erwarten kann, war es deutlich einfacher sich auf das 
wesentliche zu konzentrieren, 4 Logikfehler zu finden (wäre auch ohne 
Debugger gegangen, hat mich aber abgelenkt) und das Programm zu einem 
angenehmen Ende zu bringen. Jetzt muss ich noch an meiner Hardware 
rundherum basteln und wenn ich besonders verwegen bin, mache ich mich an 
die Umstellung auf einen ATtiny85 (dafür hatte ich mal eine Platine 
entworfen, durch den unklaren Programmlauf bin ich auf einen ATmega 
gegangen, weil ich dort debuggen konnte).

Trotzdem nochmal vielen Dank für die Hilfe

cu und schönes Wochenende

Sebastian

von Oliver S. (oliverso)


Lesenswert?

Am gezeigten Code liegt es nicht. Der ist in Ordnung, bis auf die 
Initialisierung der unsigned Werte mit -1.

Ein stack overflow verursacht solche Effekte, aber der ist aus dem 
gezeigtem Code auch nicht ersichtlich.

Ergo: Fehler in Zeile 42.

Oliver

von Sebastian (basti73)


Lesenswert?

Hallo Oliver,

danke fürs Drüberschauen. Die Initialisierung mit -1 ist gleichbedeutend 
mit 0xFFFF (das Zweierkomplement bei -1 sieht genauso aus) und hat den 
Vorteil, dass es mit allen uint funktioniert, egal welche Größe.

cu

Sebastian

von Andreas H. (ahz)


Lesenswert?

Sebastian schrieb:
> MeasureColor(background);

Hallo Sebastian

Kannst Du bitte den Code von MeasureColor() mal posten? Der fehlt leider 
in Deinem Listing und könnte evtl auch diesen Fehler erzeugen.

Und lass Dich nicht von Leuten wie Apollo ärgern. Das Forum ist ja schon 
zum helfen gedacht.

/regards

von Sebastian (basti73)


Lesenswert?

Hallo Andreas,

ich hatte die Benachrichtigung übersehen. Hier die Funktion...

Danke nochmal

cu

Sebastian
1
void MeasureColor(uint32_t * color) {
2
3
    /*
4
    S2 S3 PHOTODIODE TYPE
5
     L  L Red
6
     L  H Blue
7
     H  L Clear (no filter)
8
     H  H Green
9
     */
10
    
11
    uint32_t dbgCounter = -1;
12
    PINB = 0;
13
14
    for (int i = 0; i < 4; i++) {
15
        //set bits from color in PORTD (after rightshift)
16
        if (i & 1) {
17
            PORTD |= (1 << S3);
18
        } else {
19
            PORTD &= ~(1 << S3);
20
        }
21
        if (i & 2) {
22
            PORTD |= (1 << S2);
23
        } else {
24
            PORTD &= ~(1 << S2);
25
        }
26
27
        // wait for raising edge
28
        while (!(PIND & (1 << PIND3)) && (dbgCounter--)) {
29
        }
30
        
31
        if(!dbgCounter)
32
        {
33
            PORTB |= (1 << PINB0);
34
        }
35
        
36
        dbgCounter = -1;
37
        
38
        uint32_t count = 0;
39
        uint16_t maxloop = 2000;
40
        
41
        while(maxloop--)
42
        {
43
            while ((PIND & (1 << PIND3))) { // && (dbgCounter--)) {
44
               count++;
45
           }
46
        }
47
        
48
        color[i] = count;
49
    }
50
}

von Noch ein Kommentar (Gast)


Lesenswert?

Solltest die Frage anders stellen: Benutzt hier irgend jemand Pickit4 
und XC-8 für ATmega328P?

Wäre auch vorstellbar, die Microchip Entwickler hatten die Pic Tools nur 
Quick&Dirty auf Amtel Prozessoren portiert. Wollte halt irgendjemand aus 
der Marketingabteilung. Ist nur noch nicht aufgefallen, weil die AVR 
Programmierer bei ihren alten Tools bleiben.

von Émile (Gast)


Lesenswert?

Noch ein Kommentar schrieb:
> Benutzt hier irgend jemand Pickit4
> und XC-8 für ATmega328P?

MPLab Snap (was im wesentlichen ein abgespecktes Pickit4 ist) 
funktioniert mit Microchip Studio ganz wunderbar mit Atmega328p, egal, 
welchen C-Compiler man nun verwendet, den kastrierten XC-8 oder den 
freien gcc. Beide werden mit Microchip Studio mitgeliefert.

von Andras H. (kyrk)


Lesenswert?

Hallo,

es kann sein, dass der Compiler so viel optimiert dass der Debugger 
damit nicht mehr klar kommt. Dann kann man folgenden Trick verwenden, im 
main machst du per Hand ein paar Testfälle und schaust dir die Variablen 
dann an:

volatile int current_TC1 = -1;
volatile int expected_TC1 = 1;
volatile int result_TC1 = -1; //Not executed yet

volatile int current_TC2 = -1;
volatile int expected_TC2= 0;
volatile int result_TC2 = -1; //Not executed yet

volatile int current_TC3 = -1;
volatile int expected_TC3 = 0;
volatile int result_TC3 = -1; //Not executed yet

volatile int current_TCn = -1;
volatile int expected_TCn = 1;
volatile int result_TCn = -1; //Not executed yet

.... (oder machst einen Array)

void main(void) {
    {//TC1
        uint32_t measurement[4] = {-1, -1, -1, -1};
        uint32_t background[4]  = {-1, -1, -1, -1};
        uint32_t reference[4]   = {-1, -1, -1, -1};
        result_TC1 = CompareColors(background, measurement);
        current_TC1 = CompareColors(background, measurement);
        if (current_TC1 != expected_TC1) {
            result_TC1 = 0;//Failed
        } else {
            result_TC1 = 1;//Passed
        }
    }
    {//TC2
        uint32_t measurement[4] = { 0, -1, -1, -1};
        uint32_t background[4]  = {-1, -1, -1, -1};
        uint32_t reference[4]   = {-1, -1, -1, -1};
        current_TC2 = CompareColors(background, measurement);
        ...
    }
    {//TC3
        uint32_t measurement[4] = {.....};  //Testfälle sich ausdenken
        uint32_t background[4]  = {...};
        uint32_t reference[4]   = {....};
        current_TC3 = CompareColors(background, measurement);
        ...
    }
    {//TCn
        uint32_t measurement[4] = {-1, -1, -1, -1};
        uint32_t background[4]  = {-1, -1, -1, -1};
        uint32_t reference[4]   = {-1, -1, -1, -1};
        current_TCn = CompareColors(background, measurement);
        ...
    }
    {
        volatile int debug_catcher = -1;
        debug_catcher++;
        debug_catcher++;//Put here a breakpoint
        debug_catcher++;
        debug_catcher++;
    }
}

Dann gucken ob die Testfalle ok sind. Wenn ja dann tut die Funktion.

von Ralf G. (ralg)


Lesenswert?

Sebastian schrieb:
> Die Initialisierung mit -1 ist gleichbedeutend
> mit 0xFFFF (das Zweierkomplement bei -1 sieht genauso aus) und hat den
> Vorteil, dass es mit allen uint funktioniert, egal welche Größe.

für 'uint' nehme ich lieber '~0'.

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.