Guten Abend liebe Forumsgemeinde,
ich sitz nun schon seit einiger Zeit an meiner ersten TWI / I2C
Schaltung und verzweifle langsam.
Controller ist ein Mega32 und Slave ein PCM3070 (wobei das erstmal egal
sein sollte). Controller läuft mit dem int. Quarz auf 1MHz und der
Bustakt läuft mit 10kHz.
Ich hab mich hier in die Thematik eingelesen und soweit auch mal die
Theorie verstanden.
(http://elk.informatik.fh-augsburg.de/da/da-21/Tutorial/tutorial.html).
In der Praxis hat folgender Code die ersten Minuten funktioniert (siehe
Bild scope_37):
1
#include<avr/io.h>
2
#include<util/twi.h>
3
4
intWert;
5
intTWBR_VAL=40;
6
7
intmain(void)
8
{
9
while(1)
10
{
11
TWBR=TWBR_VAL;
12
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
13
while(!(TWCR&(1<<TWINT)));
14
TWDR=(0000000<<1)|TW_WRITE;// Hier adressiere ich alle Slaves!
15
TWCR=(1<<TWINT)|(1<<TWEN);
16
while(!(TWCR&(1<<TWINT)));
17
TWDR=Wert;
18
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
19
20
}
21
}
Auf dem Bild scope_37 erkennt man dass 7 Nullen und das SLA_W Bit
gesendet werden und der Slave die Anfrage akzeptiert was er mit einem
HIGH als ACK zurückgibt. (Was nach dem ACK das weitere HIGH soll weiß
ich allerdings noch nicht, ist das mein Wert der übertragen wird?).
So nun dachte ich mir läuft die Kiste aber Pustekuchen, wenn ich z.b.
0000111 als Adresse sende sieht das Ergebnis aus wie auf Bild 38 wo ich
def. keine Logik mehr erkennen kann weil nirgends 4 Nullen auftauchen.
Interessanterweise kann ich den PCM3070 mit der Adresse 0011000 gar
nicht ansprechen, das Ergebnis sieht aus wie auf Bild 37. Kann doch
nicht sein, oder?
Ich würde mich freuen wenn ich Tips von euch krieg :) Vielen Dank!
Gruß
Bernhard
Hallo,
Ich vermisse hier ein 'STOP' auf dem Bus. Außerdem ist das 'HIGH' zum
9.CLK ein NACK vom Slave.
Die CLK-Leitung sieht auch schon leicht verschliffen aus. Verringere mal
den Rp.
Gruß Steffen
Steffen H. schrieb:> Die CLK-Leitung sieht auch schon leicht verschliffen aus. Verringere mal> den Rp.
Wurde behoben, hat sich fälschlicherweise ein 100k Widerstand
eingeschlichen.
Steffen H. schrieb:> Ich vermisse hier ein 'STOP' auf dem Bus.
Hab ich behoben, es muss erst das Startbit gelöscht werden bevor ein
Stop gesendet werden kann.
>Außerdem ist das 'HIGH' zum 9.CLK ein NACK vom Slave.
Jop, im Tutorial stehts leider genau andersrum ist aber ein NACK wie du
richtig erkannt hast.
So, nun klappt neben dem Start auch der Stop und ich kann sehen dass der
Slave nicht reagiert. (siehe Bild 40).
Mein Code sieht dabei folgendermaßen aus:
1
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);// TWI Interrupt aktivieren, TWI starten und einschalten.
2
while(!(TWCR&(1<<TWINT)));// Warten bis der Start erfolgreich war.
3
TWDR=(0110000<<1)|TW_WRITE;// Senden des Schreibbefehles an die Slaveadresse.
4
TWCR&=~(1<<TWSTA);// Startbit löschen.
5
TWCR=(1<<TWINT)|(1<<TWEN);// TWINT setzen.
6
while(!(TWCR&(1<<TWINT)));// Warten bis Twint gesetzt ist.
Hier wird doch ganz klar die Adresse des Slaves angesprochen?! (hab ich
aus dem Datenblatt), aber warum sendet der Master lauter Nullen? Ich
schaffe es nicht den Slave anzusprechen. Ändere ich TW_Write zu TW_Read
dann geht Bit 8 von 0 auf 1, das klappt also. Nur verstehe ich nicht wie
ich den Slave adressiere. Muss ich die Adresse hier im Hexformat
eintragen?
Ein schrieb:> Wieso schreibst du 0110000?> Im Datenblatt (p.29 I²C Control) steht 0011000.
Ok sorry ganz klar mein Fehler. Aber trotzdem sollten doch nicht lauter
Nullen gesendet werden, da stimmt doch was nicht?!
Steffen H. schrieb:> Lief es mit der EinstellungTWDR = (01100000<<0); auch??
Nein da lief es nicht. Sobald die Zahl mit einer 0 angefangen hat kamen
nur Nullen raus.
Steffen H. schrieb:> Ah, vieleicht aber so:> TWDR = (0b0011000<<1) | TW_Write;> Bitte mal probieren.
Werd ich heute Abend mal probieren.
Andere Frage:
Bei dem PCM3070 wird das Routing und die DSP Einstellungen mit einer
Software von Ti erstellt. Diese Software hab ich auch bereits
installiert und ein erstes Setup gebastelt. Man kann sich dann daraus
eine .cfg Datei erstellen lassen die alle Register und Werte enthält.
Laut Ti soll man diese Datei in ein Eeprom schreiben (hat 56KByte so wie
sie jetzt ist) und beim starten mit einem µC vom Eeprom in den PCM3070
laden.
Das klingt ja theoretisch ganz einfach, praktisch hab ich da allerdings
so meine Problemchen.
Kann ich (wenn ich die Datei als hex im Eeprom liegen hab) mit dem µC
einfach eine Schleife laufen lassen die jedes Byte aus dem Eeprom
ausliest, auf sich selbst zwischenlagert und in den PCM3070 schreibt?
Das wären dann 56KByte = 56.000Byte = 56.0000 mal folgende
Vorgehensweise:
TWI Start
TWI Connect Eeprom Read
TWI Read Byte n
TWI Stop
Byte auf lokalem Controllerspeicher ablegen
TWI Start
TWI Connect PCM3070 Write
TWI Write Byte n
TWI Stop
TWI Start
TWI Connect Eeprom Read
TWI Read Byte n+1
TWI Stop
Byte auf lokalem Controllerspeicher ablegen
TWI Start
TWI Connect PCM3070 Write
TWI Write Byte n+1
TWI Stop
Bei einem Bustakt von 10KHz würde das knapp 6 Sekunden dauern. Ist diese
Vorgehensweise so ansatzweise richtig oder macht man das anders?
Gruß
Bernhard
Bernhard W. schrieb:> Nein da lief es nicht. Sobald die Zahl mit einer 0 angefangen hat kamen> nur Nullen raus.
logisch, schau Mal nach was eine mit Null beginnende Zahl für ein
Zahlenformat ist
Wenn eine Zahl mit 0 beginnt, danach aber kein b oder x kommt, dann wird
sie als Octal interpretiert. Braucht heute kein Mensch mehr, war wohl in
den 70er Jahren noch wichtig.
0110 is also
0*512 + 1*64 + 1*8 + 0
also 72 dezimal.
PittyJ schrieb:> Wenn eine Zahl mit 0 beginnt, danach aber kein b oder x kommt, dann wird> sie als Octal interpretiert. Braucht heute kein Mensch mehr, war wohl in> den 70er Jahren noch wichtig.>> 0110 is also> 0*512 + 1*64 + 1*8 + 0> also 72 dezimal.
Super, danke , kurz und verständlich erklärt.
Kann mir bei meinem anderen Problem auch jemand weiterhelfen?
Hallo Bernhard,
Ich hab mir gerade mal das Datasheet zum PCM3070 angesehen. Leider finde
ich kein Protokoll zum I2C Bus.
Aber wenn man sich die Sample-Configurations ansieht, dann denk ich es
wird:
- Start
- Device-Adresse
- Page-Adresse
- Data-Byte
- Stop
via I2C jedesmal geschrieben. Wie das Tool von TI die Config-Datei
aufgebaut hat, welches du ja in den EEPROM schreiben willst, musst du
noch raus finden. Ich hab dazu leider nichts gefunden.
Hat dein Oszi die Serial-Funktion freigeschaltet?
Wenn ja kannst du da auf I2C umschalten und wenn du dem Oszi dann
mitteilst was SCL und was SDA ist, zeigt er dir unten an was du da für
einen Brei sendest.
Kannst auch den Trigger auf I2C Start setzen ;)
Busbauer schrieb:> Hat dein Oszi die Serial-Funktion freigeschaltet?>> Wenn ja kannst du da auf I2C umschalten und wenn du dem Oszi dann> mitteilst was SCL und was SDA ist, zeigt er dir unten an was du da für> einen Brei sendest.> Kannst auch den Trigger auf I2C Start setzen ;)
Leider nein da ich bisher noch nie mit Bussystemen zu tun hatte, es ist
mein allererstes Projekt mit I2C / TWI. Werde mich am Wochenende
vermutlich weiter damit beschäftigen, hab grad keine Zeit dafür.
Danke für eure Antworten,
Gruß
Alternativ könnte man das Start Signal per Software auf einen freien Pin
ausgeben und mit dem Trigger-EIngang des Oszilloskpes verbindne.
Oder man baut eine 10ms Warteschleife vor dem Start Signal ein und
triggert auf das Ende der 10ms Pause (falls Dein Oszilloskop das kann).
Hi,
ich hab mich jetzt mal hingesetzt und mit der TruePath Software ein
Programm erstellt.
Grafisch sieht das wie auf Bild 1 aus, man kann daraus dann die .cfg
Datei erstellen lassen und bekommt dann die Register mit den Werten
(glaube ich) -> siehe Anhang!
Wie krieg ich nun am einfachsten die .cfg Datei mit einem ATmega32 über
I2C in den PCM3070?
Danke, Gruß und frohe Ostern.
Bernhard
Hallo zusammen,
aaaalso ich habs geschafft dem PCM3070 Daten zu übermitteln, wie Steffen
geschrieben hat geht es ganz einfach so:
- Start
- Device-Adresse
- Page-Adresse
- Data-Byte
- Stop
In Code ausgedrückt sieht das dann so aus:
Der Code funktioniert, man sieht am Oszi wie jede Übertragung mit ACK
bestätigt wird. Soweit so gut.
Ich sende nun also mit
1
TWI_send(add,reg,val);
meine Befehle nacheinander ab.
Die TruePath Software gibt mir nun eine Datei aus wie ich sie schon
vorher angehängt habe.
Dort sehen die Befehle folgendermaßen aus:
# # reg[0][84] = 0
w 30 54 00
# # reg[0][94] = 32
w 30 5e 20
# # reg[0][95] = 254
> fe
# # reg[0][96] = 0
> 00
# # reg[0][97] = 104
> 68
# # reg[0][98] = 168
> a8
# # reg[0][99] = 6
w steht für write, ein TWI Befehl würde dann für die erste Zeile also
wie folgt aussehen:
1
TWI_send(0x30,0x54,0x00);
Das funktioniert auch, hab ich getestet.
Bei den Befehlen mit dem > Zeichen muss man die Register hochzählen,
hier im Beispiel also 95/96/97/... und in Hex eben 5f/60/61/...
Soweit ja alles klar aber ich brauch irgend eine Routine die mir das
macht, also die Werte aus der Datei nimmt und mir in meine TWI_send();
Funktion bastelt.
Kennt jemand einen einfachen Weg das zu machen? Die Datei ist einfach zu
groß um die ganzen Befehle per Hand zu ändern.
Bis vor ein paar Tagen wusste ich noch gar nicht wie I2C überhaupt
funktioniert, bin jetzt echt froh soweit gekommen zu sein und alles
verstanden zu haben aber ich habe leider keinen Ansatz wie ich hier nun
weiter komme.
Vielen Dank für die Hilfe,
Gruß
Bernhard