Forum: Mikrocontroller und Digitale Elektronik I2C Signal wird nicht fertig gesendet


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Benjamin B. (benbu)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
Ich nutze einen PIC24FJ128GB204 als Master und möchte eine I2C- 
Verbindung zu einem FT200XD (I2C zu USB) aufbauen.
Die Verbindung kann auch aufgebaut werden. aber nach einigen Malen 
"hängt" der Controller sich beim Senden der Adresse bzw. des 
Lese/schreib Bits auf. Manchmal fängt er sich wieder und manchmal nicht.
Ich habe hier mal zwei Bilder, die den Vorgang zeigen.
Im Bild "unvollstaendigeNachricht" seht ihr den Beginn der Nachricht und 
wie plötzlich beim letzten Bit SDA auf low bleibt und SCL auf high.
Das zweite Bild (RestDerNachricht) zeigt wie 54ms später der Rest der 
Nachricht kommt. Auch, dass danach eine komplette Nachricht ohne 
Probleme gesendet wird.
Ich muss dazu erwähnen, dass der Controller vor dem Fehler bereits über 
100 Mal die Nachricht korrekt gesendet hat und das so eine Sittuation 
immer zu einem anderen Zeitpunkt kommt. Leider rettet er sich immer nur 
maximal ein mal aus so einem Zustand. Danach bleibt er komplett mit SDA 
low und SCL high stehen.

Ich habe für die Programmierung den MCC im MPLAB genutzt und vermute, 
dass dort das problem liegt, da ich nicht alles verstehe was dort 
programmiert wird. Ich teile mal den Code, den ich nutze hier:

Die Funktion, die ich aufrufe um den den Inhalt des USB speichers 
abzufragen.
1
uint8_t USB_Read(  uint8_t *pData, uint16_t nCount)
2
    {
3
        I2C2_MESSAGE_STATUS status;
4
        //uint8_t     writeBuffer[3];
5
        uint16_t    retryTimeOut, slaveTimeOut;
6
        uint16_t    counter;
7
        uint8_t     *pD;
8
9
        pD = pData;
10
11
        for (counter = 0; counter < nCount; counter++)
12
        {
13
            // this portion will read the byte from the memory location.
14
            retryTimeOut = 0;
15
            slaveTimeOut = 0;
16
17
            while(status != I2C2_MESSAGE_FAIL)
18
            {
19
                // write one byte to EEPROM (2 is the count of bytes to write)
20
                I2C2_MasterRead(pD,3,USB_ADDRESS,&status);
21
22
                // wait for the message to be sent or status has changed.
23
                while(status == I2C2_MESSAGE_PENDING)
24
                {
25
                    // add some delay here
26
                    // timeout checking
27
                    // check for max retry and skip this byte
28
                    if (slaveTimeOut == USB_DEVICE_TIMEOUT)
29
                        return (0);
30
                    else
31
                        slaveTimeOut++;
32
                }
33
34
                if (status == I2C2_MESSAGE_COMPLETE)
35
                    break;
36
37
                // if status is  I2C2_MESSAGE_ADDRESS_NO_ACK,
38
                //               or I2C2_DATA_NO_ACK,
39
                // The device may be busy and needs more time for the last
40
                // write so we can retry writing the data, this is why we
41
                // use a while loop here
42
43
                // check for max retry and skip this byte
44
                if (retryTimeOut == USB_RETRY_MAX)
45
                    break;
46
                else
47
                    retryTimeOut++;
48
            }
49
50
51
            // exit if the last transaction failed
52
            if (status == I2C2_MESSAGE_FAIL)
53
            {
54
                return(0);
55
                break;
56
57
            }
58
59
            //pD++;
60
        }
61
        return(1);
62
    }

Die Funktion, die immer wieder aufgerufen wird. (in dieser Frage ich 
erst Taster ab und dann den USB Speicher)
1
void interruptProcedure(){
2
        switchStatus=checkSwitch(); // Übergebe die Variable an SwitchStatus, welcher Taster gedrückt ist, CheckSwitch() schaut in die LookUp arrSwitch)
3
        if (switchStatus!=-1){  // wenn ungleich -1 dann wurde Taster gedrückt 
4
            if (switchStatus<16){ // wenn Nummer kleiner 16 wurde ein INPUT angewählt
5
                actInputPort = switchStatus;   //Schreibe die Nummer des INPUT in die Variable: actInputPort 
6
            }
7
            else{
8
                actOutputPort = switchStatus; // wenn Nummer größer 16, wurde ein OUTPUT angewählt, schreibe die Nummer des Input in die Variable: actOutputPort
9
            }
10
             // Setze die einzelnen Muliplexerbausteine, je nach Configuration
11
            setGates();
12
            //errorHandling(errorNumber);
13
        }
14
        
15
        
16
        // Start der USB Abfrage 
17
        // es geht immer nur lesen oder schreiben in einem Intrrupt-Durchlauf
18
        // Prüfen ob etwas im Empfangsregister liegt
19
        
20
        switch (RecievedCommand[0]){
21
            case 0x01:                             //  Setze Ports
22
                actInputPort = (int)RecievedCommand[1] ;
23
                actOutputPort = (int)RecievedCommand[2] +16;
24
                setGates();
25
                Flag_R_W = false;
26
                break;
27
                
28
            case 0x02:                             // Versions Ausgabe
29
                SendArray[0] = RecievedCommand[0];
30
                SendArray[1] = RecievedCommand[1];
31
                SendArray[2] = RecievedCommand[2];
32
                SendArray[3] = 0x01;          // Befehel OK 
33
                SendArray[4] = 0x56;          // V
34
                SendArray[5] = 0x31;          // 1
35
                SendArray[6] = 0x2E;          // .
36
                SendArray[7] = 0x30;          // 0
37
                SendArray[8] = 0x30;          // 0
38
                Flag_R_W = false;
39
                break;
40
            case 0x03:                             // Status Abfrage
41
                SendArray[0] = RecievedCommand[0];
42
                SendArray[1] = RecievedCommand[1];
43
                SendArray[2] = RecievedCommand[2];
44
                SendArray[3] = 0x01;          // Befehel OK 
45
                SendArray[4] = 0x00;          // 0
46
                SendArray[5] = 0x01;          // 1
47
                SendArray[6] = 0x00;          // 0
48
                SendArray[7] = 0x00;          // 0
49
                SendArray[8] = 0x00;          // 0
50
                Flag_R_W = false;
51
                break;
52
            case 0x04:                             // Selbsttest
53
                SendArray[0] = RecievedCommand[0];
54
                SendArray[1] = RecievedCommand[1];
55
                SendArray[2] = RecievedCommand[2];
56
                SendArray[3] = 0x01;          // Befehel OK 
57
                SendArray[4] = 0x00;          // 0
58
                SendArray[5] = 0x01;          // 1
59
                SendArray[6] = 0x00;          // 0
60
                SendArray[7] = 0x00;          // 0
61
                SendArray[8] = 0x00;          // 0
62
                Flag_R_W = false;
63
                break;
64
            case 0x05:                          // Softreset
65
                Softreset = true;
66
                SendArray[0] = RecievedCommand[0];
67
                SendArray[1] = RecievedCommand[1];
68
                SendArray[2] = RecievedCommand[2];
69
                SendArray[3] = 0x01;          // Befehel OK 
70
                SendArray[4] = 0x00;          // 0
71
                SendArray[5] = 0x00;          // 1
72
                SendArray[6] = 0x00;          // 0
73
                SendArray[7] = 0x00;          // 0
74
                SendArray[8] = 0x00;          // 0
75
                break;
76
            default:
77
                SendArray [0] = 0x00;
78
                SendArray [1] = 0x00;
79
                SendArray [2] = 0x00;
80
                SendArray [3] = 0x02;       // Fehler Befehl nicht bekannt
81
                SendArray [4] = 0xFF;
82
                SendArray [5] = 0xFF;
83
                SendArray [6] = 0xFF;
84
                SendArray [7] = 0xFF;
85
                SendArray [8] = 0xFF;
86
                Flag_R_W = true;
87
                break;
88
        }
89
        if (Flag_R_W){
90
            ERROR = USB_Read( RecieveLink, 1);
91
            
92
        }
93
        if (!Flag_R_W)
94
        {
95
            ERROR = USB_Write(SendLink ,1);
96
            RecievedCommand[0] = 0x00;
97
            RecievedCommand[1] = 0x00;
98
            RecievedCommand[2] = 0x00;
99
            
100
            
101
        }
102
    }

Vielleicht kann mir jemand einen Hinweis geben, wo ich noch suchen kann, 
oder wo der Fehler ist.
Schon mal vielen Dank im Voraus.
Grüße

von M. K. (sylaina)


Lesenswert?

Hab mir jetzt nur Bilder angeschaut aber es sieht so aus als würde da 
was den Clock stretchen. Im 8. Clockcycle bleibt der Clock high.
Hardware ist richtig verdrahtet mit passenden Pull-Ups usw.? An der 
Software, denke ich, liegts nicht. Die arbeitet idR nicht zufällig ;)

von Vanye R. (vanye_rijan)


Lesenswert?

> Software, denke ich, liegts nicht. Die arbeitet idR nicht zufällig ;)

Manchmal haut einem natuerlich ein IRQ darein. Aber das sollte I2C
abkoennen. Aber wohl nicht jede I2C Implementation kommt mit 
Clockstrechning
klar und man sollte unbedingt auch mal die Errata lesen. Gerade bei
I2C kann man da oft wunderliches finden.

Vanye

von Benjamin B. (benbu)


Lesenswert?

An ein Stretching habe ich auch schon gedacht. Aber die Hardware ist 
korrekt aufgebaut. Das habe ich mehrfach kontrolliert. (auch 
Widerstände) Wenn ich die Abfrage nur ein mal pro sekunde mache hält er 
auch (zeitlich) länger durch. daher sieht es für mich so aus, dass er 
mit irgendetwas im Code zufällig "kollidiert". Ich weiß nur nicht was es 
sein könnte. Ich habe keine weiteren Intrrups oder ähnliches eingebaut.

von Patrick C. (pcrom)


Lesenswert?

Bist du sicher das de FT200XD als SLAVE zu benutzen ist ?
...Und ist er auch as SLAVE initialisiert ?

Weiter gibt es vielleicht noch Hinweise zu sehen wenn man die SDA und 
SCL analog messt ? Oft sieht man da am Spannungsniveau wann ob der SDA 
von Master oder Slave bedient wird.

von Vanye R. (vanye_rijan)


Lesenswert?

> Ich habe hier mal zwei Bilder, die den Vorgang zeigen.

Das stimmt uebrigens nicht. Das sind Bilder von einem Logicanalyzer
dem Luegenstift der Programmierer. Bei so Lowlevelproblemen solltest
du ein Oszi nehmen um die Signale analog zu sehen.

Bei komplexen Problemen kann es hilfreich sein die GND beider ICs
ueber einen kleinen Widerstand zu verbinden an dem 0.2V oder sowas
abfaellt. Dann kannst du auf dem Oszi sehen wer wirklich deine
Leitung gerade nach unten zieht und entscheiden ob du das so erwartest.

Vanye

von Sebastian W. (wangnick)


Lesenswert?

M. K. schrieb:
> Hab mir jetzt nur Bilder angeschaut aber es sieht so aus als würde da
> was den Clock stretchen.

Die I2C-Clock wird low gestretcht. Das ist es nicht.

Mir sieht es eher danach aus, als ob die I2C-Logik des PIC während einer 
noch andauernden Übertragung von den Pins getrennt würde.

Was genau macht setGates()?

LG, Sebastian

von Rainer W. (rawi)


Lesenswert?

Patrick C. schrieb:
> Oft sieht man da am Spannungsniveau wann ob der SDA von Master oder
> Slave bedient wird.

Ganz sicher sieht man es, wenn man jeweils einen Widerstand in die SDA- 
und in die SCL-Leitung einschleift.

von Benjamin B. (benbu)


Angehängte Dateien:

Lesenswert?

Hallo Leute
Ich habe den Fehler gefunden.
Es lag an dem FT200XD dort gibt es einen Pin, der variabel genutzt 
werden kann. Diesen habe ich nach vorschlag der Dokumentation 
verdrahtet.
Ich habe ihn dann gestern mal umverdrahtet und ihm eine Funktion 
gegeben. Damit läuft es jetzt.
Im Anhang ist der Auzug aus dem Datenblatt.

Aber danke für die vielen Ideen. Durch diese habe ich an der richtigen 
Stelle gesucht.

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.