Hallo, ich Programmiere derzeit auf einem LPC2148. Ich versuche derzeit I2C in Gang zu bekommen, doch leider funktioniert es nicht ganz. Es läuft alles(Slave adressegesendet+ ACK erhalten). Aber sobald ich Daten senden will und in der ISR in I20DAT mien Daten lade undSi-Falg lösche, wird SDA auf LOw gezogen und nichts passiert, der Stautscode ist dann 0x10(also repeated start?). Auf SCL ist jedoch ein Clock mit 9 Pulsen zu sehen. Kann jemand helfen? Gruß Stephan
Ich frage nochmal, vielleicht sieht es jemand, der ein ähnliches Problem hatte. Es funtkioniert alles, bis ich Daten senden will, die Clockleitung macht auch das was sie tun soll, nur Sobald ich Daten senden will, wird SDA auf LOW gezogen, während auf SCL 9 Takte zu sehen sind. Wie schon erwähnt steht im Statuscode dann der falsche Code von 0x10, wo eigentlich 0x28 (Daten gesendet+ ACK) stehen müsste oder 0x30 für Daten gesendet und NACK erhalten. Wäre schön wenn mir jemand helfen könnte. Gruß Stephan
Moin, wie sich Dein Beitrag liest, hast Du am Bus ein Speicheroszi hängen, was sehr hilfreich bei der Fehlerdiagnose ist. Letztens hatten wir ähnliche Probleme bei einem 8051-Derivat. Wir haben ein Programmbeispiel von Atmel verwendet, das wir noch reichlich umstricken mussten. Hast Du einen Slave am Bus? Wie ist die Adresse? Wird sie korrekt umgesetzt? Die Slaves brauchen bei hohen Taktraten Pausen zwischen den Befehlen. In Basic fällt das kaum auf, aber in Assembler sehr wohl. Vielleicht hilft's Stefan
Die Slaveadresse ist 1001 dann Hardwaremäßig 000. Wie meinst du korrekt umgesetzt? Also ein ACK bekomm ich. Ich weiss dass da Pausen benötigt werden(so 10ms), aber wie kann ich die ein bauen. Mein Programm springt ja garnicht aus der ISR. Es Wird die Startcondition ausgelöst, dann ist der Statuscode 0x08, dann springt das Programm in die Behaldlung von 0x08, dann wird die Slaveadresse gesendet, dann ist der Satuscode 0x18, dann werden dort die Daten gesendet, und ich galube vor dem Daten senden müsste ich warten,oder?
1 | void I2C_ISR(void) __irq |
2 | {
|
3 | int temp1 = 0; |
4 | temp1 = I20STAT; |
5 | |
6 | switch(temp1) |
7 | {
|
8 | case 0x08: |
9 | {
|
10 | I20DAT = slaveaddr; //addr |
11 | }
|
12 | break; |
13 | |
14 | case 0x10: |
15 | {
|
16 | I20DAT = slaveaddr; |
17 | }
|
18 | break; |
19 | |
20 | case 0x18: |
21 | {
|
22 | I20DAT = 0xAA;//hier nur Beispielwert |
23 | }
|
24 | break; |
25 | |
26 | case 0x20: |
27 | {
|
28 | i2c_stop(); |
29 | }
|
30 | break; |
31 | |
32 | case 0x28: |
33 | {
|
34 | I20DAT = 0xAA;//hier nur Beispielwer |
35 | }
|
36 | break; |
37 | |
38 | case 0x30: |
39 | {
|
40 | i2c_stop(); |
41 | }
|
42 | break; |
43 | }
|
44 | I20CONCLR = (1 << SIC); // | (1 << STA); |
45 | VICVectAddr = 0; |
46 | |
47 | |
48 | }
|
Moin, zuerst wird die Adresse des Slaves gesendet: das erste gesendete Bit ist das MSB der Adresse. Die Adresse ist 7 Bit lang und das 8. Bit definiert, ob gelesen (1) oder gelesen (0) werden soll. Beim Schreiben werden also nur gerade Werte übertragen. Das lässt sich sehr gut auf dem Oszi ablesen. Die Adresse 00h ist ein "General Call", also ein Befehl an ALLE Slaves! Noch zwei Tipps: 1. Zum Testen der Routine habe ich diese einmal durchlaufen lassen und das Programm in einer Endlosschleife enden lassen. Das Oszi habe ich auf "Single Shot" gestellt und bei richtiger Einstellung der Zeitbasis kann man Takt und Daten sehr schön sehen. PS: Ich habe ein Fluke 196. 2. Zum Testen, welche "Cases" durchlaufen werden habe ich LEDs gesetzt. Viel Erfolg Stefan PS: Da sich nicht jeder mit Deinem Controller auskennt wäre es sinnvoll vor den "case"-Anweisungen diese mit aussagekräftigen Kommentaren zu versehen. Das mag Dir sinnlos erscheinen, aber es erhöht die Lesbarkeit Deines Programms. Das wirst Du aber erst in ein paar Wochen feststellen, wenn Du diese Routine noch mal nachvollziehen willst und erst wieder Handbücher wälzen darfst.
So ich habe mal die cases kommentiert. Danke für den Tip, auf sowas wie kommentieren kommt man in der Hitze des Gefechts nicht... Ich debugge des Ganze mit Hitop5, ich sehe also die cases sehr schön. DAs Problem ist nur, das folgerder Fall eintritt, der Meiner Meinung nach garnicht möglich sein sollte: Beim Senden der Daten wird SDA auf LOW gezogen und es werden ja 9 TAkte erzeugt, es werden also nur Nullen übertregen, obwohl im Datenregister ein Wert != 0 steht. Beim löschen des SI(Interrupt) Flags wird scheinbar ein repeated Start ausgefürt, jedenfalls sagt das das Statusregister und auch auf dem Oszi ist eine Startcondition zu sehen. void I2C_ISR(void) __irq { int temp1 = 0; temp1 = I20STAT; switch(temp1) { case 0x08: //Startcondition erzeugt { I20DAT = slaveaddr; //addr } break; case 0x10: //Repeated Startcondition erzeugt { I20DAT = slaveaddr; } break; case 0x18: //Slaveadresse+Writebit gesendet, ACK erhalten { I20DAT = 0xAA;//hier nur Beispielwert } break; case 0x20: ////Slaveadresse+Writebit gesendet, NACK erhalten { i2c_stop(); } break; case 0x28: //DAten gesendet ACk erhalten { I20DAT = 0xAA;//hier nur Beispielwer } break; case 0x30: //DAten gesendet NACk erhalten { i2c_stop(); } break; } I20CONCLR = (1 << SIC); // | (1 << STA); VICVectAddr = 0; }
Tach, dann überprüfe, ob I20DAT und slaveaddr korrekt initialisiert und zugeordnet worden sind. Es wäre auch zu prüfen, ob die Variablen und Register nicht versehendlich überschrieben werden. Gib in der Interruptroutine, zu Tests, die Adresse fest vor. Mit Kommentaren ist die Routine wirklich besser lesbar :o) Viel Erfolg Stefan PS: Im Anhang ist das Oszillogramm eines I²C-Schreibbefehls. Das erste Paket ist die Adresse, danach kommen zwei Pakete mit Daten.
Die Bits in ICONSET setzen sich nicht alle von selbst zurück, beispielsweise nicht STA. In den Tabellen 148+ des Manuals ist beschrieben, was im jeweiligen Zustand von der Software erwartet wird. Dazu gehört auch, diese Bits entsprechend zu setzen oder zu löschen. Beispielcode findet man in der Application Note AN10369 von NXP. PS: Seltsamerweise war vor ein paar Tagen ein anderer(?) Anwender mit gleichem Controller, gleichem Compiler und ähnlichem Problem unterwegs. Ist das grad ansteckend?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.