Forum: Mikrocontroller und Digitale Elektronik If statement wird nicht ausgeführt trotz korrektem Vergleich? (TMS320F28388D)


von DenDen (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Auf dem Communication Manager eines TMS320F28388D führe ich den lwIP 
Stack um TCP Packete zu empfangen. Wird ein Packet empfangen kopiert die 
entsprechende Callback-Routine die Daten in einen Puffer `buffer` und 
signalisiert einer Schleife in `main()` mittels flag `command_available` 
dass es Daten zu verarbeiten gibt.

In `main()` wird dann die Routine `processCommand()` aufgerufen welche 
sich das erste Byte von `buffer` anschaut. Ich kann nicht nachvollziehen 
weshalb der if branch niemals ausgeführt wird, obwohl das erste Byte in 
`buffer` 0 ist? (s. dazu auch das angehängte Video einer Debugging 
Session).

Hier sind relevante Codeausschnitte:
1
void processCommand(){
2
    uint8_t command_code=buffer[0];
3
    /*
4
    switch(command_code){
5
        case STOP_ALL:
6
            IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
7
                            STOP_ALL, (uint32_t)readData, 0);
8
            IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
9
            break;
10
        case BUCK_ENABLE_ALL:
11
            IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
12
                            BUCK_ENABLE_ALL, (uint32_t)readData, 0);
13
            IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
14
            break;
15
        default:
16
            break;
17
    }
18
    */
19
    if(command_code==(uint8_t)(0)){
20
        IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
21
                        STOP_ALL, (uint32_t)readData, 0);
22
        IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
23
        return;
24
    }
25
    else{
26
        IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
27
                        STOP_ALL, (uint32_t)readData, 0);
28
        IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
29
        return;
30
    }
31
}
1
uint8_t buffer[512];                    //a buffer storing the last received bytes
2
bool command_available=false;           //indicates whether a new command has been received via TCP

von Norbert (Gast)


Lesenswert?

Wie wird denn buffer gefüllt? Interrupt? Volatile!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

DenDen schrieb:
> kann nicht nachvollziehen weshalb der if branch niemals ausgeführt wird
Das wird der Compiler wegoptimiert haben, denn der Code macht doch beide 
Male das selbe. Oder wo müsste ich den Unterschied suchen?

: Bearbeitet durch Moderator
von Thomas Z. (usbman)


Lesenswert?

der Optimizer hat erkannt dass beide Zweige gleich sind

ups zu langsam

: Bearbeitet durch User
von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

DenDen schrieb:
> Ich kann nicht nachvollziehen
> weshalb der if branch niemals ausgeführt wird, obwohl das erste Byte in
> `buffer` 0 ist?

Warum sollte das gemacht werden? Der Programmcode ist in beiden Fällen 
der gleiche. Einmal reicht. Im Zweifelsfall schau dir mal den erzeugten 
Assembercode an...

von Falk B. (falk)


Lesenswert?

DenDen schrieb:
> uint8_t buffer[512];

Geht das auf der CPU? Die kleineren Piccolo-Brüder, die ja den gleichen 
(ähnlichen?) CPU-Kern haben, können als kleinste Einheit nur 16 Bit 
adressieren, da gibt es kein uint8_t.

von Tom (mantabit)


Lesenswert?

Norbert schrieb:
> Wie wird denn buffer gefüllt? Interrupt? Volatile!

Hier ist die entsprechende Routine:
1
// TCP received callback function is called when new data was received on COMM_PORT
2
err_t tcp_recvd_cb(void* arg, struct tcp_pcb* tcppcb, struct pbuf* p,err_t err){
3
    //payload being NULL indicated that the TCP connection has been terminated
4
    if(p->payload==NULL||p->len==0){
5
        connection_active=false;
6
        // close the pcb
7
        tcp_close(tcppcb);
8
        // listen to new connections again
9
        tcp_accept(welcoming_socket_pcb,accept_cb);
10
        return ERR_OK;
11
    }
12
    else{
13
        if(err==ERR_OK){
14
            // -- process the data in p , p is NULL if the remote host terminated the connection --
15
            memcpy(buffer,p->payload,p->len);
16
            u16_t bytes_read=p->len;
17
            //indicate that a new command is available for processing in the buffer
18
            command_available=true;
19
            // -- indicate that bytes were read and we are ready to receive more data --
20
            tcp_recved(tcppcb,bytes_read);   //indicate that no_bytes_read were read and we are ready to receive more data
21
            // -- echo the received data back
22
            tcp_write(tcppcb,buffer,bytes_read,TCP_WRITE_FLAG_COPY);
23
            return ERR_OK;
24
        }
25
        else{
26
            //wait forever and preserve debug state
27
            while(1);
28
        }
29
    }
30
}

Lothar M. schrieb:
> DenDen schrieb:
>> kann nicht nachvollziehen weshalb der if branch niemals ausgeführt wird
> Das wird der Compiler wegoptimiert haben, denn der Code macht doch beide
> Male das selbe. Oder wo müsste ich den Unterschied suchen?

Sorry, die Routine müsste eigtl. folgendermassen lauten (die beiden 
branches sind nicht gleich):
1
void processCommand(){
2
    uint8_t command_code=buffer[0];
3
    /*
4
    switch(command_code){
5
        case STOP_ALL:
6
            IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
7
                            STOP_ALL, (uint32_t)readData, 0);
8
            IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
9
            break;
10
        case BUCK_ENABLE_ALL:
11
            IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
12
                            BUCK_ENABLE_ALL, (uint32_t)readData, 0);
13
            IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
14
            break;
15
        default:
16
            break;
17
    }
18
    */
19
    if(command_code==(uint8_t)(0)){
20
        IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
21
                        STOP_ALL, (uint32_t)readData, 0);
22
        IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
23
        return;
24
    }
25
    else{
26
        IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
27
                        BUCK_ENABLE_ALL, (uint32_t)readData, 0);
28
        IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
29
        return;
30
    }
31
}

Das Problem bleibt leider bestehen.

: Bearbeitet durch User
von Phantomix X. (phantomix)


Lesenswert?

Ich weiß nicht inwiefern dein Chip Ähnlichkeiten zum TMS320F2808 hat, 
mit dem hab ich damals in der Diplomarbeit gearbeitet.

Schau dir bitte mal sizeof(char) an. Beim 2808er sind das nämlich 16 
Bit, d.h. der Chip kann keine kleineren Dateneinheiten verarbeiten 
(evtl. Bits einzeln noch)

bei
1
uint8_t command_code=buffer[0];

könnte es also sein, dass du in Wirklichkeit 16 Bits deines Datenstromes 
in command_code speicherst (wobei ich mich dann frage, weshalb es 
überhaupt ein uint8_t gibt, das solle dann nämlich nicht definiert sein 
um solche Fehler zu vermeiden)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

DenDen B. schrieb:
> Das Problem bleibt leider bestehen.
Ich würde mir hier jetzt mal den zugehörigen vom Compiler erzeugten 
Assemblercode ansehen...

Beitrag #6868995 wurde vom Autor gelöscht.
von Phantomix X. (phantomix)


Lesenswert?

Hat der Chip ein Daten-Caching? Vielleicht hat die CPU was anderes im 
Cache als der DMA im Hintergrund vom Ethernet ins RAM geschrieben hat? 
kopfkratz

von Tom (mantabit)


Angehängte Dateien:

Lesenswert?

Ok, wenn ich via TCP '0000' sende befinden sich im Speicher tatsächlich 
die falschen Werte (vier mal b'00110000' stat b'00000000'), siehe auch 
Bild im Anhang.

Die Variablenvorschau in CCS zeigt allerdings 'unsigned char 0' an.

: Bearbeitet durch User
von Christian E. (cerker)


Lesenswert?

0x0011000 = 0x30 = 48 ist der ASCII-Code von '0'.
Du sendest also "0000" als Text.

Die Variablenvorschau interpretiert wohl char als einen .. Char. Das ist 
das Zeichen '0', nicht die Zahl 0.

: Bearbeitet durch User
von Tom (mantabit)


Lesenswert?

Christian E. schrieb:
> 0x0011000 = 0x30 = 48 ist der ASCII-Code von '0'.
> Du sendest also "0000" als Text.
>
> Die Variablenvorschau interpretiert wohl char als einen .. Char. Das ist
> das Zeichen '0', nicht die Zahl 0.

Das ist es, vielen Dank!

Der `uint8_t` wird als `unsigned char` definiert weshalb mir die 
Variablenvorschau `0` anzeigt:
1
#elif defined(_TMS320C6X) || defined(__ARM_ARCH) || defined(__ARP32__) || \
2
      defined(__PRU__)    || defined(__C7000__)
3
    typedef   signed char   int8_t;
4
    typedef unsigned char  uint8_t;
5
    typedef          short  int16_t;
6
    typedef unsigned short uint16_t;
7
    typedef          int    int32_t;
8
    typedef unsigned int   uint32_t;

Das Problem ist also nicht der uC Code sondern das Python Skript, 
welches die Daten sendet.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

DenDen B. schrieb:
> unsigned char 0'

char ist aber auf dieser CPU-Familie 16 Bit breit!

von Tom (mantabit)


Lesenswert?

Falk B. schrieb:
> DenDen B. schrieb:
>> unsigned char 0'
>
> char ist aber auf dieser CPU-Familie 16 Bit breit!

Der Communication Manager besitzt eine ARM Cortex M4 Architektur (der 
Chip besitzt einen ARM CM und zwei C28 CPUs).

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.