Hallo zusammen,
ich habe mir ein kleines Mikroncontroller Board gebaut. Darauf befindet
sich ein ATmega32u2 und ein AD-Wandler MCP3426. Das ganze ist mit USB
und der LUFA Library über einen VirtualSerialPort an den Computer
verbunden und lässt sich darüber ansteuern. Der AD-Wandler wird über
eine I2C-Schnittstelle angesteuert, nun sind leider die tollen SLD und
SDA Funktionen auf anderen Pin's die schon belegt sind und auch nicht
geändert werden können. Also muss ein Software I2C-Master her. Da das
Protokoll ja eigentlich schön ausführlich in dem Datenblatt des
ADC-Wandels erklärt ist habe ich erst eine Ewigkeit mein eigenes Glück
herausgefordet und versucht eine Kommunikation her zu stellen. Leider
erfolglos, entweder es ist überhaupt nichts passiert oder das Programm
hat sich aufgehängt und es ging nichts mehr.
Also habe ich mir gedacht, warum das Rad zwei mal erfinden, solche I2C
Software Implementierungen muss es doch schon zur genüge geben denn ich
werde sicherlich nicht der erste sein beim dem es von den Pin's her
nicht passt.
Nach etwas suchen habe ich auch ein paar Open-Source-Libraryies
gefunden, jedoch bin ich mir nicht sicher ob diese wirklich das können
was ich brauche denn dieser ADC-Wandler ist doch recht speziell an sich.
Außerdem habe ich an beiden Pin's Interrupts zur Verfügung die bestimmt
für etwas bessere Performance sorgen könnten wenn diese mitverwendet
werden.
Könnt ihr mir Software I2C Libraries empfehlen?
Am besten mit Interrupt Unterstützung und ggf. mit deutscher
Dokumentation, wobei ich auch der englischen Sprache mächtig bin.
ATmega32U2
http://www.atmel.com/images/doc7799.pdfMCP3426http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
I2C Library
http://extremeelectronics.co.in/avr-tutorials/software-i2c-library-for-avr-mcus/
LUFA
http://www.fourwalledcubicle.com/LUFA.php
Samuel Müller schrieb:> oder das Programm> hat sich aufgehängt und es ging nichts mehr.
Dann hast Du was falsch gemacht.
Der Master gibt alle Timings vor, d.h. er wartet eine bestimmte Zeit und
setzt oder liest einen Pin. D.h. er ist immer irgendwann fertig.
Schlimmstenfalls sind die Daten Müll oder Du kriegst ein NACK, das ist
alles.
Samuel Müller schrieb:> Außerdem habe ich an beiden Pin's Interrupts zur Verfügung die bestimmt> für etwas bessere Performance sorgen könnten wenn diese mitverwendet> werden.
Wie sollen denn diese Interrupts getriggert werden?
Wie gesagt, es sind Timings einzuhalten, mehr nicht. Die sind allerdings
so kurz, daß ein Timerinterrupt nicht lohnt (viel zuviel
Stack-Overhead).
Danke für die Antworten, wie Peter Dannegger es geschrieben hat macht
die verwendugn von Interrups natürlich keinen Sinn.
Ich habe mich nun für die Lib von Peter Fleury entschieden, da diese
wohl schon sehr oft verwendet wurde und gut zu funktionieren scheint.
Erfolgreich eingebunden bin ich nun direkt auf mein nächstes Problem
gestoßen, irgend etwas bei der Kommunikation scheint wohl nicht zu
klappen.
Die if-Bedingung wird jedes mal erfüllt.
1
voidtest_ad(){
2
unsignedcharret;
3
4
#define Adress 0xd
5
6
DDRB=0xff;// use all pins on port B for output
7
PORTB=0xff;// (active low LED's )
8
9
i2c_init();// init I2C interface
10
11
// write 0x75 to eeprom address 0x05 (Byte Write)
12
ret=i2c_start(Adress+I2C_WRITE);// set device address and write mode
13
if(ret){
14
// failed to issue start condition, possibly no device found
15
i2c_stop();
16
PORTB=(Adress+I2C_WRITE);
17
}
Schön wäre es hier natürlich ein Oszi zu haben -.-
Als Adresse habe ich "1101" aus dem Datenblatt (Seite 19) entnommen.
Das würde ja einem "d" in hex entsprechen, habe es auch schon mit d0, b
und b0 versucht, jedes mal das selbe Ergebnis.
Mein nächster Gedanke war das die delays zwischen den gesendeten Bits
nicht stimmt. Dazu konnte ich folgenden Code aus der Assembler Datei
entnehmen:
1
.stabs"",100,0,0,i2c_delay_T2
2
.stabs"i2cmaster.S",100,0,0,i2c_delay_T2
3
.funci2c_delay_T2;delay5.0microsecwith4Mhzcrystal
4
i2c_delay_T2:;4cycles
5
rjmp1f;2"
6
1: rjmp 2f ; 2 "
7
2:rjmp3f;2"
8
3: rjmp 4f ; 2 "
9
4:rjmp5f;2"
10
5: rjmp 6f ; 2 "
11
6:nop;1"
12
ret ; 3 "
13
.endfunc;total20cyles=5.0microsecwith4Mhzcrystal
Aus den Kommentaren konnte ich keine explizite Anweisung entnehmen das
hier etwas am Code geändert werden muss, jedoch verwende ich einen 16MHz
Kristall und kann auch nirgens eine Verknüpfung mit F_CPU finden.
Nachtrag:
Laut Kommentar soll die Wartezeit für Normal ja 5us dauern und für fast
1,3us. Da mein ADC-Baustein ja den fast mode unterstützt und dies bei
meinen 16MHz ziemlich genau 20Takte sind (hoffentlich habe ich mich
nicht verrechnet), sollte zumindest mit der Zeit ja alles passen oder?
Da I2C ein getakteter Bus ist, ist es erst mal nicht besonders kritisch,
wenn dein Master langsamer arbeitet als er könnte.
Ich denke eher, dass hier
> Als Adresse habe ich "1101" aus dem Datenblatt (Seite 19) entnommen.
das Problem liegt.
Das erste Byte in der I2C Übertragung ist eine Kombination aus Adresse
und Modus. Das unterste Bit (LSB) gibt an, ob vom Baustein gelesen oder
zum Baustein geschrieben werden soll. Die restlichen 7 Bit sind die
Adresse. D.h. die Adresse muss um 1 Bit nach links geshiftet in das zu
übertragende Byte eingehen.
Nun ist es leider so, dass aus den Datenblättern oft nicht hervorgeht,
ob die angebene Adresse diese Verschiebung bereits berücksichtigt hat
oder nicht.
Die Fleury Lib will auf jeden Fall die bereits um 1 Bit verschobene
Adresse haben.
D.h. dein Adresse kann 0x0D sein, sie könnte aber auch um 1 Bit nach
links geschoben 0x1A lauten.
Für letzteres spricht zum Beispiel, dass in 0x0D ja bereits das unterste
Bit auf 1 ist. D.h. mittels
1
ret=i2c_start(Adress+I2C_WRITE);
bzw.
1
ret=i2c_start(Adress+I2C_READ);
wäre es gar nicht mehr möglich, da jemals ein 0 Bit rein zu bringen.
(d.h. mit einer Addition wäre das schon möglich. Aber eigentlich sollte
da ja auch nicht + stehen sondern |)
Ähm.
Deine Datenblatt INterpretation der Sache mit der Adresse ist aber
höchst eigenwillig.
Denn dort steht nicht das, was du da im Thread behauptet hast.
Da steht
1
ThefirstbyteaftertheSTARTbitisalwaystheaddress
2
byteofthedevice,whichincludesthedevicecode(4
3
bits),addressbits(3bits),andR/Wbit.Thedevice
4
codeforthedevicesis1101,whichisprogrammedat
5
thefactory.TheI2Caddressbits(A2,A1,A0bits)are
6
asfollows:
Auf der nächsten Seite ist sogar eine Zeichnung, wie die Bits im ersten
I2C Byte aufzufassen sind
1
7 6 5 4 3 2 1 0
2
+---+---+---+---+---+---+---+---+
3
| 1 | 1 | 0 | 1 | A2| A1| A0| M |
4
+---+---+---+---+---+---+---+---+
d.h. die Hex D finden sich im höherwertigen Nibble wieder, während das
untere Nibble aus den auf deiner Schaltung beschalteten Eingängen A2 bis
A0 ergibt und dazu dann noch das Modus-Bit für Schreiben oder Lesen.
D.h. je nachdem wie A2 bis A0 beschaltet sind, hast du eines der
Adress-Bytes
Meine Überlegungen gingen in die selbe Richtung wie deine Karl Heinz.
Jedoch habe ich wie oben beschrieben auch schon das ganze mit 0xD0
ausprobiert und kein anderes Resultat erzielt. Die Adress Bits A0, A1
und A2 scheinen bei meinem Baustein (MCP3426) keine Rolle zu spielen,
heißt wohl es ist egal welche Werte sie besitzten?
Anbei noch mal der Ausschnitt aus dem Datenblatt über den wir gerde
reden.
Samuel Müller schrieb:> Die Adress Bits A0, A1> und A2 scheinen bei meinem Baustein (MCP3426) keine Rolle zu spielen,> heißt wohl es ist egal welche Werte sie besitzten?
Was heißt 'scheinen'?
Die sind auf der Platine die du hast irgendwie verkabelt. Schau halt auf
die Platine wie genau sie verschaltet sind.
Nix 'scheinen'. 'wissen' ist gefragt.
In meinem ersten Beitrag ist das Schaltbild des Bausteines zu erkennen
auf dem deutlich "sichtbar" keine Adresspins vorhanden sind. Hier vlt
noch ein Satz aus dem Datenblatt "The MCP3427 and MCP3428 have two
external
device address pins (Adr1, Adr0).".
Da diese Pins bei mir nicht vorhanden sind "scheinen" die Adress Bits
bei mir keine Rolle zu spielen da in diesem Zusammenhang nicht weiter
auf die Version MCP3426 eingegangen wird.
Samuel Müller schrieb:> Da diese Pins bei mir nicht vorhanden sind "scheinen" die Adress Bits> bei mir keine Rolle zu spielen da in diesem Zusammenhang nicht weiter> auf die Version MCP3426 eingegangen wird.
Jein.
Im Datenblatt steht, dass sie beim 26-er factory programmed sind. D.h.
irgendeine der 8 Adressen ist die richtige.
Also ich verstehe das so, das nur der Device Code programmiert ist. Aber
ich will ja nichts unversucht lassen, darum habe ich es direkt ein mal
ausprobiert mit 0xD0 bis 0xDE und habe wieder kein positives Resultat
erzielt -.-
Samuel Müller schrieb:> Also ich verstehe das so, das nur der Device Code programmiert ist.
Im Datenblatt steht explizit, dass die Adressen (nicht nur der Device
Code) factory programmed sind.
Ich würde mal davon ausgehen, dass der Hersteller die Adresse 0xD0
genommen hat (also die Adressbits alle 0). Allerdings: wenn er das immer
so gemacht hat, dann wäre das auch so dokumentiert. Er hat sich also
eine Hintertür offen gelassen.
> Aber> ich will ja nichts unversucht lassen, darum habe ich es direkt ein mal> ausprobiert mit 0xD0 bis 0xDE und habe wieder kein positives Resultat> erzielt -.-
Tja. Jetzt hast du ein Problem.
Entweder bist du auf der falschen Adresse oder es ist sonst noch was
falsch, oder beides.
Es ist halt nie gut, wenn man zuviele Unbekannte im Spiel hat.
Hast du denn nicht noch einen Prozessor, bei dem du Hardware-TWI zur
Verfügung hast, so dass man erst mal davon ausgehen kann, dass I2C
grundsätzlich funktionieren müsste?
Alternativ: hast du ein anderes I2C-IC, dessen Adresse du kennst?
Ziel der Sache ist es, erst mal etwas Stochern-im-Nebel durch Bekanntes
zu ersetzen.
Leider nicht, das ist eine fertig zusammengelötete Platine und an dem
I2C-Bus hängt nur der AD-Wandler dran. Ich hätte zwar noch einen
Controller, Wandler, Widerstände und Kondensatoren aber das alles
freiluft zu verkabeln würde wohl eher noch mehr Fehlerquellen eröffnen
anstatt sie zu reduzieren.
Kann ich nicht z.B. über den Interrupt und eine LED eine Art debugging
machen das ich sehe ob der Baustein überhaupt irgend etwas macht oder
meine Kommunikationsversuche komplett ignoriert.
Für die Adresse kann ich theoretisch auch ne Schleife einbauen, das mein
Controller einfach alle verfügbaren Adressen durchprobiert.
Samuel Müller schrieb:> Für die Adresse kann ich theoretisch auch ne Schleife einbauen, das mein> Controller einfach alle verfügbaren Adressen durchprobiert.
Genau so.
Erstmal nur die Adresse senden und prüfen, ob ein ACK kommt.
Immer Schritt für Schritt vorgehen:
http://www.youtube.com/watch?v=ncFCdCjBqcE
Also ich habe mir nun eine Schleife gebaut die jede mögliche Adesse
probiert und wenn ein ACK kommt mir diese an den LED's anzeigen soll.
Leider auch hier kein Ergebnis.
1
while(Adress<0xff){
2
3
ret=i2c_start(Adress);
4
if(ret){
5
i2c_stop();
6
}
7
else{
8
PORTB=(Adress);
9
}
10
Adress+=1;
11
}
Nun habe ich auch mal den analogen Multiplexer ausgelötet der an dem
Analogeingang des ADC angebracht ist, trotzdem nichts.
Mittlerweile frage ich mich wirklich ob der ADC noch richtig
funktioniert, denn softwaremäßig kann ja jetzt eigentlich nciht mehr
viel falsch sein oder?
>Gibt es irgend eine Möglichkeit heraus zu finden ob das Bauteil noch>richtig funktioniert?
Ja, korrekte I2C Routinen schreiben und das Viech
damit abfragen. Auf den Rücken legen und mit einem
Kugelschreiber drauf rumdrücken wird wohl nichts bringen.
Ich kenn die Fleury-Lib nicht.
Warum da Assembler verwendet wird, ist komisch.
I2C ist nicht zeitkritisch, kann man also komplett in C schreiben.
Häng mal 2 LEDs (+R) gegen VCC an SDA und SCL, die müssen bei Traffic
flackern bzw. ohne Traffic aus sein.
Hab vor Jahren für den 8051 mal diesen Supersimpel-Soft-I2C geschrieben.
Kein clock stretching, kein multimaster, aber wenig Code und
funktioniert.
Mit minimaler Arbeit kann man das für den AVR adaptieren. I2C ist keine
Raketenwissenschaft.
holger schrieb:> Ja, korrekte I2C Routinen schreiben und das Viech> damit abfragen. Auf den Rücken legen und mit einem> Kugelschreiber drauf rumdrücken wird wohl nichts bringen.
Fachlich ziemlich daneben würde ich mal sagen, vielleicht solltest du
deine Zeit lieber in einem Forum über Tiere verbringen.
Peter Dannegger schrieb:> Ich kenn die Fleury-Lib nicht.> Warum da Assembler verwendet wird, ist komisch.> I2C ist nicht zeitkritisch, kann man also komplett in C schreiben.>> Häng mal 2 LEDs (+R) gegen VCC an SDA und SCL, die müssen bei Traffic> flackern bzw. ohne Traffic aus sein.
Heißt ich könnte das versuchsweise auch mal mit ms Delays probieren?
Bei den normalen 5us wird da ja wohl nicht sehr viel zu sehen sein.
Hmpf, wenn ich mir meinen alten Code da anschaue, könnte man da einige
Sachen auf Anhieb besser machen. ;) Z.B. könnte man den Typ vom
Parameter "ack" bei i2c_read auf unsigned char ändern. Wie auch immer,
als Basis sollte das passen.
Samuel Müller schrieb:> Heißt ich könnte das versuchsweise auch mal mit ms Delays probieren?
Du kannst auch Sekunden nehmen. I2C ist nicht zeitkritisch, da die
Übertragung getaktet ist. Siehe gregs Code.
Warum P.Fleury das in Assembler gemacht hat, erschliesst sich mir auch
nicht wirklich. Die Hardware-I2C ist in C geschrieben.
Nimm gregs Code und überarbeite ihn für den M32. Ist nicht wirklich viel
Arbeit. Das bisschen Pin hoch, Pin runter ist nicht die Welt.
greg schrieb:> Hmpf, wenn ich mir meinen alten Code da anschaue, könnte man da> einige> Sachen auf Anhieb besser machen. ;) Z.B. könnte man den Typ vom> Parameter "ack" bei i2c_read auf unsigned char ändern. Wie auch immer,> als Basis sollte das passen.
Danke für das Beispiel, ich werde es mir morgen direkt mal ansehen,
möchte ja nichts unversucht lassen.
Zur Sicherheit habe ich direkt mal noch einen neuen AD-Wandler bei
Reichelt bestellt, wie ich die kenne dauert das aber bestimmt noch ne
Weile bis der kommt.
>Fachlich ziemlich daneben würde ich mal sagen, vielleicht solltest du>deine Zeit lieber in einem Forum über Tiere verbringen.
Leg dich besser nicht mit den grossen Jungs an.
Vieleicht solltest du deine Zeit mal damit verbringen
die I2C Spec zu lesen. Das hast du sicher nicht getan.
Lies deine Frage noch mal
>Gibt es irgend eine Möglichkeit heraus zu finden ob das Bauteil noch>richtig funktioniert?
Es ist ein Bauteil was per I2C angesteuert wird. Wie soll
man das ohne korrekte I2C Routinen schaffen?
Der einzige der hier in den Zoo gehört bist du.
Selbst mit fremder Hilfe schaffst du es nicht so etwas
simples wie einen I2C Baustein auszulesen.
Ist deine Schaltung überhaupt in Ordnung?
Besorg dir mal ein Speicherosci oder einen Logicanalyzer.
Dann reden wir weiter.
hilfesuchender schrieb:> Kann mir jemand erklären welche Pins für diese Lib verwenden werden?
Die kannst Du frei wählen.
SSDA, SSDA_DDR, SDA_PIN und SSCL, SSCL_DDR
definierst Du entsprechend aus der "sbit.h".
Auch wenn der Trend etwas älter ist!
Ich möchte gern den Code von Peter Dannegger verwenden!
Beitrag "Re: Soft I2C Master"
Habe aber nicht ganz verstanden wie ich ein Byte von einem I2c Slave mit
Nack lesen Kann!
Kann es mir jemand erklären!
Vielen Lieben Dank
Und ein frohes Fest!
Ich versteh die Frage nicht.
Was ist an der Funktionssignatur
1
staticuint8_tsi2c_r(uint8_tnack)// input NACK
unklar?
rufst du si2c_r mit einem 0 als Argument auf, dann wird ein ACK
gesendet. Rufst du es mit einer 1 als Argument auf, dann wird ein NACK
generiert.
So wie hier
der kleine Nils schrieb:> Aber warum verwendet Peter 16Bit Variablen?
Man haette die rw Funktion auch mit einer lokalen Variablen machen
können, wenn du das meinst.
Die für dich relevanten funktionen
Vielen Dank für deine Hilfe!
Also verstehe ich richtig das die Funktion si2c_r für Read steht und die
Funktion si2c_w für write?
Ich also nur die zwei Funktionen Verwenden brauche wenn ich einen
I2C_ADC auslesen will?
Danke für deine Geduld!
Habe etwas herum experimentiert!
Ich musste damit ich vernünftige Daten auf dem Bus (I2c_Sniffer von
Peter)
den Takt um eine 10 Potenz verkleinern!
So geht es aber ich verstehe nicht warum es mir dem großen Takt nicht
geht!
Danke für Eure Hilfe
der kleine Nils schrieb:> So geht es aber ich verstehe nicht warum es mir dem großen Takt nicht> geht!
Das ist nur ein einfacher Master ohne SCL-Stretching Support. Der kann
daher nur einfache Slaves und keine I2C-MCs ansteuern.
Der Sniffer ist aber ein MC und benutzt SCL-Stretching.