Archiv verlassen und diese Seite im Standarddesign anzeigen : Frage zu RP6 I2C Library: Funktionen der Lib von Peter Fleury?
teamohnename
18.02.2012, 19:46
Hallo an alle,
wir haben eine Frage zu der I²C Master Library des RP6’. In der Library von Peter Fleury gibt es z.B. i2c_stop oder i2c_rep_start. Diese Funktionen werden anscheinend von einigen Slaves benötigt. Wie kann man sowas mit der RP6 I2C Master Library machen? Hier ein Code Beispiel, (damit wir einfach verstehen, wie das mit der RP6 Library funktioniert):
[...]
i2c_start_wait(ADR+I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(ADR+I2C_READ);
b1 = i2c_readAck();
b2 = i2c_readAck();
b3 = i2c_readNak();
i2c_stop();
[...]
Bei dem Beispiel will der Slave das i2c_rep_start und das i2c_stop wie gesagt unbedingt haben.
Wäre das Beispiel dann in der RP6 Library das?
I2CTWI_transmitByte(ADR,0x07);
I2CTWI_readRegisters(ADR+1, 0x07, sensorBuf, 3);
//Daten in sensorBuf[0] - sensorBuf[2]
Vielen Dank für Eure Hilfe und
Viele Grüße
teamohnename (http://www.teamohnename.de/)
@teamohnename:
Im Prinzip ist das Beispiel der RP6 Library so richtig, wobei sogar noch die ADR bei transmit und readRegisters gleich bleiben kann (also nicht ADR+1) und der Parameter 0x07 im readRegisters weg muss.
Die Lib sendet Ack und Nack automatisch. Schau dir die ISRs in beiden Libs an!
teamohnename
19.02.2012, 20:22
Hi Dirk,
danke für Deine Antwort.
Was soll da denn anstatt 0x07 (ist das Startregister, was ausgelesen werden soll) stehen? Wenn man das weglässt, meckert der Compiler doch?! Oder haben wir Dich falsch verstanden?
Grüße
teamohnename
Hi,
dass ab Register 7 gelesen werden soll, hast du ja dem Slave vermutlich ja schon mit I2CTWI_transmitByte(ADR,0x07) mitgeteilt.
Der I2CTWI_readBytes-Befehl (NICHT ..._readRegisters,- das ist ein Bytearray der Lib!) kennt nur 3 Parameter.
Was ist das denn für ein Slave?
teamohnename
21.02.2012, 18:12
Hi Dirk,
das ist ein MLX90614 Infrarot Thermometer. Hier der Originalcode (http://dexterindustries.com/howto/working-with-avr/atmega48-and-the-mlx90614/).
Folgendes ist jetzt zwar OT, aber egal.
Wir haben den Sensor schon angeschlossen und ein paar Dinge beobachtet:
1) Mit dem Code:
I2CTWI_transmitByte(0x5A,0x07);
I2CTWI_readBytes(0x5A, sensorBuf, 3);
mlx90614_l = sensorBuf[0];
Bekommen wir im Terminal ,,I2C ERROR - TWI STATE: 0x20". Wenn wir aber schreiben:
I2CTWI_transmitByte(0x5A<<1,0x07);
I2CTWI_readBytes(0x5A<<1, sensorBuf, 3);
mlx90614_l = sensorBuf[0];
Kommt der Fehler nicht mehr, sensorBuf ist aber immer 255 (egal ob sensorBuf[0], [1] oder [2]).
Wenn man aber jetzt die I²C Verbindung unterbricht, bleibt der Wert 255 und es gibt keinen Error im Terminal.
Dass mit dem letzten Codebeispiel kein Error mehr erscheint, ist doch ein gutes Zeichen, oder? Hängt das mit dem kein-Error-ohne-Verbindung irgendwie mit dem Programm bzw. der I²C ISR zusammen, sodass das auch normal ist?
Wie sollen wir jetzt weiter vorgehen? Der Sensor scheint sich ja angesprochen zu fühlen. Das Problem ist also nur, dass wir momentan mit dem letzten Codeausschnitt noch keine Daten auslesen können... Vielleicht kann man da auch noch weiteres aus dem Originalcode übersetzen, wir wissen nur nicht wie...
Vielen Dank deshalb weiterhin für Eure Hilfe und
Viele Grüße
teamohnename
EDIT:
Hier nochmal der Code, der wirklich übersetzt werden muss, wobei das Fett geschriebene die I²C Sache ist:
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x07);
// read
i2c_rep_start(dev+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // zero out the data
int frac; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
@teamohnename:
Der MLX90614 braucht ja wohl sehr genau die Befehlsfolge, die du auch schon angegeben hast. Ob die RP6-I2C-Lib die SMBus-kompatibel genau so sendet, kann ich nicht sicher sagen.
Was man probieren könnte:
1. Den I2C-Takt auf 50 kHz heruntersetzen
2. Als Adresse für den MLX90614 0x00 probieren
3. SlyD (den Autor der RP6-Libs) fragen, ob man die Befehlsfolge so mit der RP6-Lib hinbekommt
Teste es mal mit I2CTWI_readRegisters - wegen dem repeated start.
teamohnename
21.02.2012, 20:14
Hallo Dirk und SlyD,
I2C Takt haben wir jetzt erstmal auf 50kHz heruntergesetzt.
Wir haben jetzt alle Variablen (sensorBuf und die Variable, in die sensorBuf übergeben wird) als int32_t deklariert. Jetzt ist der Wert nicht mehr 255, sondern -1. Auch, wenn wir als Adresse 0x00 probieren.
Mit I2CTWI_readRegisters haben wir es auch schon probiert, ohne Erfolg.
Wie gesagt, wenn wir den Sensor selbst (wir benutzen übrigens die 3.3V Version, da nur die in Deutschland zu haben war, mit einem 3,3V Spannungswandler und einem Pegelwandler, bei dem aber alles zu funktionieren scheint (3,3V Pegel (auch I2C) auf dem Oszilloskop kontrolliert)) aus dem Steckboard entfernen, wird nicht mehr in sensorBuf geschrieben, wir bekommen I2C Error 0x20 im Terminal. Sobald wir den Sensor wieder reinstecken, verschwindet der Fehler aber und wir bekommen als Wert wieder -1.
Deutet die -1 eventuell auf einen Overflow hin? Das wird übrigens mit writeIntegerLCD ausgegeben. Das darf ja bis zu int16_t Variablen benutzt werden...
Danke und
Viele Grüße
teamohnename
EDIT:
Gerade im Datenblatt gelesen:
8.4.6 Commands
RAM and EEPROM can be read both with 32x16 sizes. If the RAM is read, the data are divided by two, due
to a sign bit in RAM (for example, TOBJ1 - RAM address 0x07h will sweep between 0x27ADh to 0x7FFF as the
object temperature rises from -70.01°C to +382.19°C).
Der Wert in Register 0x07 schwankt also, so wie ich das verstanden habe, zwischen Dezimal 10157 und 32767, von daher müsste das ja locker in eine int16_t Variable passen...
EDIT2:
Schade. Dann werden wir wohl oder übel die Library von Peter Fleury ausprobieren müssen.
teamohnename
22.02.2012, 17:27
*push*
Hallo,
Das Portieren der Lib von Peter Fleury ist uns nun doch etwas zu schwer...
Wir fragen noch ein letztes Mal, danach werden wir wohl oder übel aufgeben müssen:
Woran kann das liegen?
Nochmal: Es gibt anscheinend keine Hardware Fehler (wenn man den Sensor aus dem Steckbrett entfernt, gibt es I2C Error 0x20). Der Sensor scheint also nach der ersten Anfrage (nachdem also 0x07 gesendet wurde) zu antworten. Danach scheint es aber Probleme zu geben. Wir können die Ergebnisse anscheinend nicht richtig aus dem Sensor auslesen (egal, welches Register ausgelesen werden soll, das Ergebnis ist immer -1, dabei ist aber ein seltsames ,,flackern" (als wenn da ganz schnell eine Zeile von unten nach oben an und aus geht) bei der -1 zu beobachten, das ist nicht so, wenn normal etwas aufs Display ausgegeben wird).
Falls es keine Lösung gibt :(, trotzdem danke für Eure Hilfe bis jetzt und
Viele Grüße
teamohnename
EDIT:
Hier ein paar Bilder vom Oszilloskop. Einmal ein ganzer Block, dann der Anfang, dann das Ende. ABer wahrscheinlich könnt ihr damit auch nicht so viel anfangen. Geld ist SCL, Blau ist SDA.
215902159121592
EDIT2:
gerade hier (http://www.mikrocontroller.net/topic/166713) gelesen:
laut datenblatt kann der sensor kein read oder write byte, sondern nur
word.
Was bedeutet das?
In dem Topic scheint der Ersteller ein ähnliches oder das gleiche Problem zu haben, wie ich, es wird vom Ersteller aber keine Antwort gepostet...
Was meint ihr?
EDIT3:
gerade im Datenblatt gelesen:
8.4.2 Differences with the standard SMBus specification (reference [1])
There are eleven command protocols for standard SMBus interface. The MLX90614 supports only two of
them. Not supported commands are:
• Quick Command
• Byte commands - Sent Byte, Receive Byte, Write Byte and Read Byte
• Process Call
• Block commands – Block Write and Write-Block Read Process Call
Supported commands are:
• Read Word
• Write Word
Das bestätigt das obere Zitat.
Was bedeutet das denn jetzt im Klartext? Was ist ein ,,word"? Eine 16bit Variable? Vielleicht sogar eine 32bit Variable?
Kommen wir dem Ziel damit näher? :D
Viele Grüße
teamohnename
teamohnename
23.02.2012, 16:55
Hallo an alle,
sorry für den Dreifachpost, ich rechtfertige das jetzt damit, dass ich neue, eventuell ausschlaggebende Ergebnisse habe und ein paar Feststellungen gemacht habe:
1) Auf den vorherigen Bildern vom Oszilloskop war noch die Kommunikation mit einem anderen Slave drauf, was ich vergessen hatte, im Code auszukommentieren. Jetzt sieht das ganz anders aus!
2) Das Ergebnis auf dem Scope ist nicht gleich, wenn die Adresse 0x00 (Bild 1) oder 0x5A<<1 (Bild 2) ist, das Ergebnis ist aber bei folgendem Code gleich:
I2CTWI_readRegisters(0x5A<<1,0x07, sensorBuf, 3);
//I2CTWI_transmitByte(0x5A<<1,0x07);
I2CTWI_readBytes(0x5A<<1, sensorBuf, 3); (Bild 1)
3) Nach wie vor fehlt die Hälfte der Signale, wenn der Sensor herausgezogen wird (Bild 3). Der scheint also wirklich zu antworten, wird dann aber anscheinend nicht richtig ausgelesen... Wie man auf Bild 1-3 sieht, sind bei SDA (blau) zum Schluss drei ,,Ausschläge" (I²C Acks des Sensors?), dazwischen ist alles 0. Ich glaube, dass dort das MSB, das LSB und das PEC sein sollten. Die sind aber alle 0. Bei Adresse 0x00 stimmt das auch anscheinend alles exakt mit dem Diagramm im Datenblatt überein, bis auf die drei Daten, die eben alle 0 sind.
Und nochmal, was meint ihr, woran könnte das liegen? Die Ursache ist ja anscheinend geklärt, jetzt müssen wir nur noch herauskriegen, wie wir das Problem beseitigen können?!
Hier die Bilder:
216012160221603
Vielen, vielen Dank für Eure Hilfe und
Viele Grüße
teamohnename
Die zeitliche Auflösung der Aufnahmen erlaubt leider keine Beurteilung dessen, was dort tatsächlich an Daten ausgetauscht wurde. Eigentlich bräuchte man zu Vergleichszwecken einmal die Kommunikation (im Detail) mit der RP6-Lib und mit der Fleury-Bibliothek.
Außerdem stocherst du noch immer im Nebel rum. Es wäre keine große Kunst, sich genau anzusehen was der Code von Fleury im vergleich zur RP6-Lib anders macht.
mfG
Markus
teamohnename
24.02.2012, 21:20
Hallo,
ja, das gebe ich zu, die zeitliche Auflösung ist mies, war aber eben nur einfacher abzufotografieren. :D Leider kann ich das Oszilloskop nur momentan noch nicht an den PC anschließen, ich muss also abfotografieren...
Ich habe das ganze jetzt mit einem ATmega8 und der Library von Fleury getestet, dort funktioniert das nahezu perfekt - nahezu. Bei der Adresse 0x00 funktioniert (mit dem Mega8!) alles perfekt, komplett wie im Datenblatt, die Werte ändern sich, wenn man z.B. mit der Hand über dem Sensor ist. Bei 0x5A sieht das aber schon anders aus - anscheinend wird richtig initialisiert, aber das, was da zurückkommt, ist die Adresse, also 0x5A (im Bild vorsichtshalber erstmal als ,,???" gekennzeichnet)...
In Sachen RP6 kann ich da allerdings nichts draus deuten - ich bekomme immer noch 0 zurück, obwohl das sehr ähnlich aussieht, bis auf die Sendepause nach dem Repeated Start...
Naja, hier jetzt vernünftige Fotos. Ich hoffe, dass da jetzt alles passt, ich habe auch etwas kommentiert, wo ich vermute, was was bedeutet.
Die Adresse ist bei einem Foto 0x5A und bei einem anderen Foto 0x55, das liegt daran, dass ich es immerhin zusätzlich mit einem Mega8 geschafft habe, die Adresse des Sensors zu ändern (natürlich mit einem anderen Code, Adresse muss aber so oder so früher oder später geändert werden).
Bitte schaut Euch die Fotos nochmal an, auch wenn wir damit weiterhin im Nebel stochern - wer weiß...
Bild 1 = ATmega8, Adresse 0x00
Bild 2 = ATmega8, Adresse 0x5A
Bild 3 = RP6, Adresse 0x00
Bild 4 = RP6, Adresse 0x55
A = Ack
RS = Repeated Start
W = Write
R = Read
Vielen Dank und
Viele Grüße
teamohnename
21615216162161721618
Hallo,
so damit kann man schonmal was anfangen.
Das liegt wohl daran das beim Code der RP6Lib da schlicht kein Repeated Start gesendet wird.
Da wird gestoppt und neu gestartet.
Setzt vorraus, dass das Register zwischengespeichert wird - macht der Sensor aber wohl nicht und
braucht das alles in einer Transaktion.
Kann man natürlich ändern.
Ist bei der RP6Lib alles in der Interrupt Routine und task_I2CTWI - also komplexer als die Fleury Lib damit noch anderes nebenher laufen kann.
Muss ich mir bei Gelegenheit mal anschauen aber eigentlich habe ich da grad keine Zeit für daher wäre es gut wenn ihr euch das selbst anschaut.
Hinweise:
-->im TWCR Register das TWSTA Bit 1 setzen für Start. TWSTO --> Stop.
Rest steht im ATMEGA Datenblatt.
In der ISR müsste man halt nen Sonderfall einführen (also nen Flag setzen das ein Repeated start benötigt wird und das dann eben
machen anstatt stop senden - für die normalen RP6 Slaves sollte es weiter so laufen wie es aktuell ist)
Glaube im Zustand TWI_MTX_DATA_ACK - da bei // Send Stop after last Byte das Stop wegmachen also 0 << TWSTO...
Die eigentliche Anfrage der Datenbytes wird dann in task_I2CTWI gestartet (daher auch die Pause - das passiert halt irgendwann
wenn die Hauptschleife da wieder vorbeikommt der Controller also Zeit hat sich drum zu kümmern ;) ).
Im Prinzip müsste es für einen ersten Test schon reichen das TWSTO in Zeile 381 auf 0 zu setzen .
Alles ohne Gewähr kann auch sein das man noch was anderes ändern muss.
Ist viele Jahre her das ich den Code geschrieben habe und mir das Datenblatt dazu
durchgelesen hab. Zeit zum testen hab ich nicht.
...
Zeile 381: ...(rep<<TWSTO)...
rep darf nur 0 oder 1 sein - 1 für normal - 0 für repeated start.
Machste dann ne neue Funktion oben hin wie eine von den anderen und setzt das da eben auf 1 - in allen anderen auf 0.
Sorry aber das ist nur Quick&Dirty - hab zuviel anderes zu tun zur Zeit um mich da genauer mit zu befassen und das zu testen hoffe die Tipps helfen euch schon um es selbst zu lösen.
MfG,
SlyD
teamohnename
24.02.2012, 23:44
Hi SlyD,
danke für Deine Antwort.
Habe ich es richtig verstanden, dass ich theoretisch nur die ISR bearbeiten muss und direkt unter ,,case TWI_MTX_DATA_ACK" abfragen muss, ob ich einen Repeated start brauche oder ein stop?
Wie findet der Roboter denn heraus, ob der Sensor einen repeated start benötigt? Was kommt also in die if-Abfrage? Das ist mir noch nicht ganz klar, das finde ich auch niergends im Datenblatt. Der Roboter müsste ja dazu in die Zukunft sehen?! :)
Danke nochmal und
Viele Grüße
teamohnename
EDIT: Oder hat das was mit den Codes in Figure 87 oder 89 des ATmega32 Datenblattes zu tun? Dann hätte sich für mich auch die Frage mit ,,in-die-Zukunft-sehen" geklärt (der Master erkennt das dann am vorherigen Verhalten des Slaves?!). :D
Die Werte aus diesem Diagramm stehen ja in TWSR. Einzig logisch wäre meiner meiner Meinung nach nur Figure 87, da der Master zu dem Zeitpunkt noch im Sendemodus ist und erst einen Repeated Start senden muss, bevor er neu anfragt und in den Receivermodus geht. Laut dem Datenblatt sendet der Slave (MLX90614) nachdem die Schreibeadresse und 0x07 gesendet wurde ein Ack. Der Code, der dann in TWSR stehen würde, wäre dann theoretisch 0x28. Dann müsste man unter ,,case TWI_MTX_ADR_ACK" rep=1 schreiben. Wo müsste dann aber rep = 0 stehen, also ein Stop eingeleitet werden?
Der Roboter müsste ja dazu in die Zukunft sehen?!
;) nein ich meinte DU legst fest ob Dein Slave das braucht oder nicht!
Im Programmcode.
aber rep = 0 stehen, also ein Stop eingeleitet werden?
Ne ist invertiert.
Nenn die variable no_rep dann isses logischer ;)
no_rep muss in ALLEN transmit / read funktionen oben auf 1 gesetzt werden.
Dann kopier Dir die eine die Du für den Sensor brauchst und änder die um, setzt es da auf 0 und setzt es in task_I2CTWI wieder auf 1.
MfG,
SlyD
teamohnename
25.02.2012, 13:35
Hi,
sorry, aber entweder ich bin zu blöd dafür oder es ist falsch...
Was meinst Du mit transmit/read Funktionen? Die I2C Read etc. aus der Library oder meine selbst geschriebenen, die die einzelnen Sensoren abfragen? Ersteres wäre ja sinnlos...
Es ändert sich am Oszilloskop nur etwas, wenn ich direkt in der ISR TWSTO komplett ändere, dass generell kein STop mehr gemacht wird, dann gibt es aber auch wieder einen Error.
Habe ich es denn wenigstens richtig verstanden, dass ich in die task_i2c() no_rep auf 1 setzen soll, vor jede eigene Funktion auch no_rep auf 1 setze und dieses dann in der Routine zum Abfragen des Sensors auf 0 setze, dass das also dann so aussieht:
//no_rep wird in der ISR vor TWSTO eingetragen, in task_i2c() am Anfang auf 1 gesetzt und in dieser einen Funktion auf 0 gesetzt
void getIR(void)
{
no_rep_start = 0;
I2CTWI_transmitByte(0x00,0x07);
I2CTWI_readBytes(0x00, sensorBuf, 3);
}
Vielen Dank und
Viele Grüße
teamohnename
In den I2CTWI_transmit Funktionen in der Lib - direkt bevor TWCR gesetzt wird - muss das auf 1 gesetzt werden.
In den anderen Funktionen könnte man es auch setzten - geht aber glaub ich auch ohne.
no_rep sollte übrigens ein uint_8t sein.
In der task_I2CTWI sollte dann in der if(TWI_operation)
no_rep auf 1 gesetzt werden....
Im einfachsten fall einfach immer ohne unterscheidung welcher Zustand.
readRegisters kannst Du dann übrigens nicht dafür verwenden - das müsste auch noch passend modifiziert werden mit zusätzlichem Zustand in der task_I2CTWI... aber egal. Probier erstmal das.
I2CTWI_transmitByteREPEATED_START(0x00,0x07); <<<---- Deine Eigene Funktion
I2CTWI_readBytes(0x00, sensorBuf, 3);
müsste dann aber klappen.
MfG,
SlyD
teamohnename
25.02.2012, 19:26
Hallo,
no_rep_start wird jetzt in allen i2c Transmit Funktionen über der TWCR Zuweisung auf 1 gesetzt, außer in einer Funktion I2CTWI_transmitByteREPEATED_START(0x00,0x07);), dort wird es über TWCR auf 0 gesetzt. Auf 1 gesetzt wird es in der task_I2CTWI in if(TWI_operation).
Diese Variable wird dann nur in Zeile 381 der I2CMaster Libs TWSTO zugewiesen:
case TWI_MTX_DATA_ACK: // Data byte has been transmitted and ACK received
if (TWI_bufPos < TWI_msgSize) {
TWDR = I2CTWI_buf[TWI_bufPos++];
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| //
(0<<TWWC); //
} else { // Send STOP after last byte
TWI_statusReg.lastTransOK = 1; // Set status bits to completed successfully.
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(no_rep_start<<TWSTO)| // Initiate a STOP/REP_START condition.
(0<<TWWC); //
}
break;
Sonst niergends!
Das Resultat ist der TWI Error 0x30.
Wenn ich in meiner neuen, angepassten Funktion:
void I2CTWI_transmitByte_RepeatedStart(uint8_t targetAdr, uint8_t data)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data;
TWI_statusReg.all = 0;
no_rep_start = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
Das no_rep_start auf 1 setze, ist alles wie vorher...
Muss eventuell noch irgendwas (ein TWSTO) mit no_rep_start gesetzt oder ergänzt werden?
Danke und
Viele Grüße
teamohnename
Hallo,
die Bedeutung der Fehlercodes steht übrigens in der Header Datei.
In diesem Fall kam ein NACK nach nem Datentransfer zurück.
> Auf 1 gesetzt wird es in der task_I2CTWI in if(TWI_operation).
wo genau? Muss ganz oben gemacht werden nicht unter den Fallunterscheidungen.
(also wieder bevor TWCR gesetzt wird)
> Muss eventuell noch irgendwas (ein TWSTO) mit no_rep_start gesetzt oder ergänzt werden
Schon möglich. Wie gesagt - ich hab keine Zeit das zu testen das oben gesagte war alles
frei aus dem Kopf ohne nochmal ins Datenblatt zu schauen.
MfG,
SlyD
teamohnename
25.02.2012, 20:16
Hi,
wenn es ganz oben in task_I2CTWI steht, ist auch wieder alles wie vorher, also ohne Repeated Start...
Was könnte denn noch geändert werden müssen? Wenn Du keine Zeit hast, ist das auch erstmal nicht so schlimm... Wir werden dann wohl noch etwas experimentieren müssen... Aber wenn Dir noch etwas einfällt; nur her damit! ;)
Vielen, vielen Dank für Deine Hilfe bis jetzt und
Viele Grüße
teamohnename
Hier übrigens nochmal ein Bild vom Scope, wie es war, als das Nack kam:
21622
Hi,
SlyD hatte gesagt, dass das no_rep = 1 nicht ganz oben in der task_I2CTWI, sondern nach if(TWI_operation) eingefügt werden soll:
void task_I2CTWI(void)
{
if (!I2CTWI_isBusy()) {
if (TWI_statusReg.lastTransOK) {
if(TWI_operation) {
no_rep = 1;
...
Probier das doch mal!
teamohnename
25.02.2012, 20:49
Hi Dirk,
danke für Deine Antwort.
Zuletzt hat SlyD doch gesagt, dass das nach ganz oben muss?!
Wenn ich das unter die Abfragen mache, kommt die Fehlermeldung und das, was ich zuletzt als Bild gepostet habe am Oszilloskop.
Viele Grüße
teamohnename
EDIT:
Anscheinend haben wir den Fehler gefunden, nachdem wir uns nochmal das Datenblatt angeschaut haben. Vorher war das so in der ISR:
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(no_rep_start<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
Dabei würde aber ein Stop durchgeführt werden, wenn no_rep_start 1 ist. Wenn das 0 ist, passiert irgendwas anderes, auf jeden Fall kein Repeated Start, da ein Repeated Start nur durchgeführt wird, wenn das so aussieht:
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a REPEATED START condition.
(0<<TWWC); //
Jetzt haben wir das so in eine if-Abfrage gepackt:
if(no_rep_start == 1){
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
}
else{
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a REPEATED START condition.
(0<<TWWC); //
}
Jetzt wird definitiv ein repeated Start gesendet, nachdem die Leseanfrage gesendet wird, bricht der Slave aber mit einem Nack ab (Fehlercode 0x48).
Woran könnte das liegen? Wahrscheinlich ja an der Lesefunktion, wenn man die ausklammert, ist der Fehler da nicht mehr. Was muss man da aber ändern?
EDIT2:
Das Nack liegt daran, dass no_rep_start nicht wieder auf 1 zurückgesetzt wird, nachdem es in der Transmit Funktion auf 0 gesetzt wurde.
Woran liegt das? Vermutlich ja an task_i2c... Aber wo muss das jetzt genau hin?
EDIT3:
So haben wir den test durchgeführt:
void getIR(void)
{
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
while(no_rep_start == 0){} //hier bleibt der Code hängen
I2CTWI_readRegisters(0x55<<1, 0x07, sensorBuf, 3);
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
//mlx90614_l = (((sensorBuf[1] & 0x007F) << 8) + sensorBuf[0]);
}
Wenn wir jetzt aber neben no_rep_start = 1 eine LED anschalten, geht diese an...
Komisch.
Hi,
müßte beim Rep-Start nicht auch TWIE auf 1 gesetzt werden?
teamohnename
25.02.2012, 21:57
Hallo Dirk,
anscheinend nicht, das steht so im Datenblatt:
A REPEATED START condition is generated by writing the following value to TWCR:
TWCR TWINT TWEA TWSTA TWSTO TWWC TWEN – TWIE
Value 1 X 1 0 X 1 0 X
Grüße
teamohnename
EDIT:
Ist wohl kein WYSIWYG Editor hier... Nichtmal in der Code Ansicht. Egal, steht im ATmega32 Datenblatt auf S. 184 fast ganz unten.
Stimmt, aber SlyD hat weiter unten das so gemacht:
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a (RE)START condition.
(0<<TWWC); //
teamohnename
25.02.2012, 22:21
Stimmt... Dann wird ein TWI Interrupt aktiviert. Wenn ich das aber so mache, schmiert das Programm auf dem RP6 ab. Wenn das Interrupt deaktiviert ist, bekomme ich die Fehlermeldung da.
SlyD hat irgendwann hier im Thread gesagt, dass man ggf. bei einer Receive Funktion irgendwas im task_i2c ergänzen muss. Wahrscheinlich war das gemeint.
Danke und
Grüße
teamohnename
EDIT:
Ich fasse nochmal das aktuelle Problem zusammen:
Es wird jetzt ordnungsgemäß ein Repeated Start duchgeführt. Danach kommt aber eine Fehlermeldung, und zwar, dass der Slave mit einem Nack abgebrochen hat (Error 0x48). Diese Fehlermeldung kommt bei allen Read Funktionen, wobei es auch egal ist, welche Slave Adresse dort eingetragen wird. Wenn ich die Read Funktion weg lasse, kommt die Fehlermeldung nicht mehr, es wird immer noch ein Repeated Start gesendet (Repeated Start ist ja auch richtig, damit dürfte das mit dem Senden geklärt sein).
Problem ist also die Lesefunktion. Was genau da nicht stimmt, weiß ich nicht. SlyD hat einmal gesagt, dass man evtl. noch eine Abfrage in task_i2c ergänzen muss...
@SlyD: Vielleicht könntest Du kurz erläutern, was das Problem ist und wie man das dann entsprechend in task_i2c lösen kann?
Zuletzt hat SlyD doch gesagt, dass das nach ganz oben muss?!
Nein nicht nach ganz oben natürlich das was ich davor gesagt hatte galt natürlich immer noch also innerhalb der IF Bedingung nach oben.
Zum Repeated Start:
OK passt schon so.
Problem ist also die Lesefunktion; Anscheinend macht die Probleme.
Beim read Aufruf wird wieder ein Start gesendet.
Check das auch mal auf dem Oszi - eigentlich müssten dann da zwei Starts hintereinander kommen.
Deswegen meinte ich auch das da noch bisschen was anderes geändert werden müsste und das alles eben in EINE transaktion gehört (sprich: einen Funktionsaufruf in der Lib - der Rest wird dann in der Lib gemacht).
Deswegen müsste man da eigentlich noch einen weiteren Zustand in task_I2CTWI einführen - eben für request mit Rep start und da dann kein 1<<TWSTA mehr setzen.
Ggf. könnte mans auch von dem no_rep_start flag abhängig machen (und es dann nach dem TWCR aufruf da zurücksetzen) und die vorhandenen benutzen aber k.a. ob dann noch alle anderen Funktionen ordnungsgemäß laufen. Dann ginge es wie bisher mit zwei Aufrufen.
(allerdings nicht mit readRegisters wie Du das oben gemacht hast)
MfG,
SlyD
teamohnename
26.02.2012, 11:54
Das sieht auf dem Oszi jetzt mit dem Code:
void getIR(void)
{
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
//[...] Weitere Bearbeitung der Variablen, keine weiteren Abfragen
}
so aus:
21623
Das sind aber keine zwei Starts, oder?
Grüße
teamohnename
EDIT:
Müsste man also bei task_i2c eine neue else if Abfrage und einen neuen TWI TRANSMISSION STATE hinzufügen, der dann in der neuen Frage abgefragt wird? Also z.B.
//in RP6I2CMasterTWI.h
#define I2CTWI_REQUEST_BYTES_REP_START 4
//in task_i2c
else if (TWI_operation == I2CTWI_REQUEST_BYTES_REP_START) {
no_rep_start = 1;
I2CTWI_delay();
TWI_msgSize = I2CTWI_request_size + 1;
I2CTWI_request_adr = I2CTWI_request_adr | TWI_READ;
I2CTWI_buf[0] = I2CTWI_request_adr | TWI_READ;
TWI_statusReg.all = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
TWI_operation = I2CTWI_READ_BYTES_FROM_BUFFER;
}
Wo muss dann TWI_operation auf 4 gesetzt werden? In einer Read Funktion?
EDIT2:
Wir kommen gerade überhaupt nicht weiter... Wir glauben auch nicht wirklich, dass das irgendetwas mit einem zweiten Start zu tun haben könnte...
Was muss jetzt genau wo ergänzt werden? Ist wenigstens unser Ansatz richtig?
Sorry für die Nerverei... Aber anders kommen wir nicht weiter, die ganze RP6 Lib ist ohne diese Erklärungen viel zu komplex für uns...
EDIT3:
Unser task_i2c sieht bis jetzt so aus:
Alles Fett gedruckte haben wir geändert.
void task_I2CTWI(void)
{
if (!I2CTWI_isBusy()) {
if (TWI_statusReg.lastTransOK) {
if(TWI_operation) {
if(TWI_operation == I2CTWI_SEND_REGISTER) {
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = I2CTWI_request_adr;
I2CTWI_buf[1] = I2CTWI_request_reg;
TWI_statusReg.all = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
if(no_rep_start == 1)
{
TWI_operation = I2CTWI_REQUEST_BYTES;
}
else
{
TWI_operation = I2CTWI_REQUEST_BYTES_REP_START;
}
}
else if (TWI_operation == I2CTWI_REQUEST_BYTES_REP_START) {
I2CTWI_delay();
TWI_msgSize = I2CTWI_request_size + 1;
I2CTWI_request_adr = I2CTWI_request_adr | TWI_READ;
I2CTWI_buf[0] = I2CTWI_request_adr | TWI_READ;
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
TWI_operation = I2CTWI_READ_BYTES_FROM_BUFFER;
}
else if (TWI_operation == I2CTWI_REQUEST_BYTES) {
I2CTWI_delay();
TWI_msgSize = I2CTWI_request_size + 1;
I2CTWI_request_adr = I2CTWI_request_adr | TWI_READ;
I2CTWI_buf[0] = I2CTWI_request_adr | TWI_READ;
TWI_statusReg.all = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
TWI_operation = I2CTWI_READ_BYTES_FROM_BUFFER;
}
else if (TWI_operation == I2CTWI_READ_BYTES_FROM_BUFFER) {
TWI_operation = I2CTWI_NO_OPERATION;
if(I2CTWI_requestID!=-1)
I2CTWI_requestedDataReadyHandler(I2CTWI_requestID) ;
}
}
}
else {
uint8_t errState = I2CTWI_getState();
if(errState != 0) {
TWI_operation = I2CTWI_NO_OPERATION;
TWI_statusReg.lastTransOK = 1;
I2CTWI_request_adr = 0;
I2CTWI_requestID = 0;
I2CTWI_request_size = 0;
I2CTWI_transmissionErrorHandler(errState);
}
}
}
}
Das ist unsere Transmit Funktion:
void I2CTWI_transmitByte_RepeatedStart(uint8_t targetAdr, uint8_t data)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data;
TWI_statusReg.all = 0;
no_rep_start = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
Und das unsere Read Funktion:
uint8_t I2CTWI_readByte(uint8_t targetAdr)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
if(no_rep_start == 1)
{
TWI_operation = I2CTWI_REQUEST_BYTES;
}
else
{
TWI_operation = I2CTWI_REQUEST_BYTES_REP_START;
}
I2CTWI_request_adr = targetAdr;
I2CTWI_requestID = -1;
I2CTWI_request_size = 1;
while(TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
if (TWI_statusReg.lastTransOK)
return I2CTWI_recbuf[1];
else
return 0;
}
Die I2C ISR sieht so aus:
uint8_t no_rep_start; //Wird ein Repeated start vom Slave benötigt?
ISR (TWI_vect)
{
static uint8_t TWI_bufPos = 0;
switch (TWSR)
{
case TWI_START: // START has been transmitted
case TWI_REP_START: // Repeated START has been transmitted
TWI_bufPos = 0; // Set buffer pointer to the TWI Address location
case TWI_MTX_ADR_ACK: // SLA+W has been transmitted and ACK received
case TWI_MTX_DATA_ACK: // Data byte has been transmitted and ACK received
if (TWI_bufPos < TWI_msgSize) {
TWDR = I2CTWI_buf[TWI_bufPos++];
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| //
(0<<TWWC); //
} else { // Send STOP after last byte
TWI_statusReg.lastTransOK = 1; // Set status bits to completed successfully.
if(no_rep_start == 1){
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
}
else{
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a REPEATED START condition.
(0<<TWWC); //
}
}
break;
case TWI_MRX_DATA_ACK: // Data byte has been received and ACK transmitted
I2CTWI_recbuf[TWI_bufPos++] = TWDR;
case TWI_MRX_ADR_ACK: // SLA+R has been transmitted and ACK received
if (TWI_bufPos < (TWI_msgSize-1) ) { // Detect the last byte to NACK it.
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after reception
(0<<TWWC); //
} else { // Send NACK after next reception
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send NACK after reception
(0<<TWWC); //
}
break;
case TWI_MRX_DATA_NACK: // Data byte has been received and NACK transmitted
I2CTWI_recbuf[TWI_bufPos] = TWDR;
TWI_statusReg.lastTransOK = 1; // Set status bits to completed successfully.
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
break;
case TWI_ARB_LOST: // Arbitration lost
TWI_TWSR_state = TWSR; // Store TWSR
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a (RE)START condition.
(0<<TWWC); //
break;
default:
TWI_TWSR_state = TWSR; // Store TWSR
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins
(0<<TWIE)|(1<<TWINT)| // Disable Interupt
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // No Signal requests
(0<<TWWC);
break;
}
}
Und so unsere Funktion zum Abfragen des Sensors:
void getIR(void)
{
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
}
So sieht das auf dem Oszilloskop aber immer noch aus, wie bei dem Bild in diesem Post oben.
Was muss noch geändert werden?
teamohnename
26.02.2012, 19:31
So, wir sind einen Schritt weiter - allerdings wissen wir ab jetzt wirklich nicht mehr weiter:
Wenn man in unserer neuen else if Abfrage in task_i2c das hier:
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
zu dem:
TWCR = (1<<TWEN)|(1<<TWIE)|(0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
ändert, können wir damit:
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
und damit (bewirkt das gleiche):
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
I2CTWI_readBytes(0x55<<1, sensorBuf, 1);
das MSB abfragen - Juhu!
ALLERDINGS: Das Programm bzw. die I2C Kommunikation stürzt ab, sobald das MSB 255 ist und sobald man zwei Bytes abfragen möchte, also hiermit:
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
uint8_t irlsb = I2CTWI_readByte(0x55<<1);
und hiermit:
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
I2CTWI_readBytes(0x55<<1, sensorBuf, 2);
Anscheinend wird ja mit TWINT das I2C Interrupt deaktiviert - sollte man vielleicht doch dort nach dem Fehler suchen?
Danke und
Viele Grüße
teamohnename
EDIT:
Gerade mal das Bild am Scope pausiert, kurz bevor die Kommunikation abschmiert: Zum Schluss wird nach dem MSB ein Stop durchgeführt. Wenn das MSB 255 erreicht, wird SDA auf low gezogen, wo es vorher high war - liegt das am Slave oder wird ein Repeated Start durchgeführt?
Hier zwei Bilder davon - einmal, solange der Wert unter 255 ist, danach, wenn er 255 ist, ein Bruchteil einer Sekunde nach Bild 2 stürzt alles ab.
2163721638
Also TWINT darfste nicht deaktivieren sonst ist klar das bei zwei Bytes nix mehr funktioniert - der Empfang läuft ja in der Interrupt Routine! Das wird nur einmal zu beginn in der task_I2CTWI angestoßen.
Die ISR wird ausserdem sobald der Rep Start ausgeführt wurde wieder aufgerufen und landet im state TWI_REP_START, da dort kein break ist läufts dann in die nächsten Zustände rein (ja ist absichtlich so).
Ggf. setz doch mal no_rep_start=1 da in dem Zustand oder alternativ in der neuen if bedingung in DATA_ACK.
teamohnename
27.02.2012, 17:39
Gut, haben wir wieder zurückgeändert.
Wenn no_rep_start in TWI_REP_START auf 1 gesetzt wird, können wir das MSB nun abfragen, ohne TWINT zu deaktivieren, allerdings stürzt die Kommunikation immer noch ab (SDA wird immer noch auf Low gezogen), zwei Bytes können wir abfragen, allerdings nur einmal, danach stürzt die Kommunikation auch ab.
Wir kommen der Sache aber näher!
Vielen Dank für weitere Tipps!
EDIT:
MYSTERIÖS:
Anscheinend ist des Rätsels Lösung gefunden. Wenn man drei Bytes hintereinander empfängt, stürzt nichts ab. Naja. Egal. Jetzt läuft es! :D
Vielen, vielen, vielen Dank an alle, die uns hier geholfen haben uns ganz besonders an SlyD. Es ist nicht selbstverständlich, dass der Entwickler einer solchen Library in so einem Forum ist und dann auch noch so freundlich und mit so viel Ausdauer hilft! ;)
Ah sehr gut - gern geschehen! :)
Es wäre natürlich noch gut, wenn Ihr für andere hier im Forum die evtl. mal was ähnliches brauchen noch die funktionierende Lösung posten würdet.
teamohnename
28.02.2012, 18:06
Klar. Hier unsere RP6I2CmasterTWI.c (RP6Lib/RP6common/RP6I2CmasterTWI.c):
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> BASE CONTROLLER
* ----------------------------------------------------------------------------
* ------------------- [c]2006 / 2007 - AREXX ENGINEERING ---------------------
* -------------------------- http://www.arexx.com/ ---------------------------
* ************************************************** **************************
* File: RP6I2CmasterTWI.h
* Version: 1.0
* Target: RP6 Base & Processor Expansion - ATMEGA32 @8.00 or 16.00MHz
* Author(s): Dominik S. Herwald
* ************************************************** **************************
* Description:
* For functional description of the TWI Master lib s. RP6I2CmasterTWI.c!
*
* ************************************************** **************************
* CHANGELOG AND LICENSING INFORMATION CAN BE FOUND AT THE END OF THIS FILE!
* ************************************************** **************************
*/
#ifdef RP6I2C_SLAVE_TWI_H
#error YOU CAN NOT INCLUDE TWI I2C MASTER AND SLAVE ROUTINES AT THE SAME TIME!
#else
#ifndef RP6I2C_MASTER_TWI_H
#define RP6I2C_MASTER_TWI_H
/************************************************** ***************************/
// Includes:
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
/************************************************** ***************************/
union TWI_statusReg {
uint8_t all;
struct {
volatile unsigned lastTransOK:1;
unsigned unusedBits:7;
};
};
extern volatile union TWI_statusReg TWI_statusReg;
extern uint8_t i2c_req_adr;
extern uint8_t TWI_operation;
extern uint8_t no_rep_start;
#define I2CTWI_isBusy() ((TWCR & (1<<TWIE)))
// Sample TWI transmission states, used in the main application.
#define I2CTWI_NO_OPERATION 0
#define I2CTWI_SEND_REGISTER 1
#define I2CTWI_REQUEST_BYTES 2
#define I2CTWI_READ_BYTES_FROM_BUFFER 3
#define I2CTWI_BUFFER_SIZE 16 // Set this to the largest message size that will be sent including address byte.
#define I2CTWI_BUFFER_REC_SIZE 48 // Set this to the largest message size that will be received including address byte.
#define I2CTWI_initMaster(__FREQ__) __I2CTWI_initMaster((uint8_t)((F_CPU/(2000UL*__FREQ__))-8))
void __I2CTWI_initMaster(uint8_t twi_bitrate);
void I2CTWI_setRequestedDataReadyHandler(void (*requestedDataReadyHandler)(uint8_t));
void I2CTWI_setTransmissionErrorHandler(void (*transmissionErrorHandler)(uint8_t));
void task_I2CTWI(void);
uint8_t I2CTWI_getState(void);
void I2CTWI_requestDataFromDevice(uint8_t requestAdr, uint8_t requestID, uint8_t numberOfBytes);
void I2CTWI_requestRegisterFromDevice(uint8_t targetAdr, uint8_t requestID, uint8_t reg, uint8_t numberOfBytes);
void I2CTWI_getReceivedData(uint8_t *msg, uint8_t msgSize);
void I2CTWI_readBytes(uint8_t targetAdr, uint8_t * messageBuffer, uint8_t numberOfBytes);
uint8_t I2CTWI_readByte(uint8_t targetAdr);
void I2CTWI_readRegisters(uint8_t targetAdr, uint8_t reg, uint8_t * messageBuffer, uint8_t numberOfBytes);
void I2CTWI_transmitByte(uint8_t adr, uint8_t data);
void I2CTWI_transmitByte_RepeatedStart(uint8_t adr, uint8_t data);
void I2CTWI_transmit2Bytes(uint8_t adr, uint8_t data1, uint8_t data2);
void I2CTWI_transmit3Bytes(uint8_t targetAdr, uint8_t data1, uint8_t data2, uint8_t data3);
void I2CTWI_transmit4Bytes(uint8_t targetAdr, uint8_t data1, uint8_t data2, uint8_t data3, uint8_t data4);
void I2CTWI_transmitBytes(uint8_t targetAdr, uint8_t *msg, uint8_t numberOfBytes);
#define TWI_READ 1
#define TWI_GEN_CALL 0
/************************************************** ***************************/
// TWI Status Codes:
// The TWI status codes were taken from ATMEL AN315!
// General TWI Master staus codes
#define TWI_START 0x08 // START has been transmitted
#define TWI_REP_START 0x10 // Repeated START has been transmitted
#define TWI_ARB_LOST 0x38 // Arbitration lost
// TWI Master Transmitter staus codes
#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been transmitted and ACK received
#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been transmitted and NACK received
#define TWI_MTX_DATA_ACK 0x28 // Data byte has been transmitted and ACK received
#define TWI_MTX_DATA_NACK 0x30 // Data byte has been transmitted and NACK received
// TWI Master Receiver staus codes
#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been transmitted and ACK received
#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been transmitted and NACK received
#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK transmitted
#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK transmitted
// TWI Slave Transmitter staus codes
#define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned
#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
#define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received
#define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received
#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
// TWI Slave Receiver staus codes
#define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned
#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
#define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned
#define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78 // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_ACK 0x80 // Previously addressed with own SLA+W; data has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_NACK 0x88 // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
#define TWI_SRX_GEN_DATA_ACK 0x90 // Previously addressed with general call; data has been received; ACK has been returned
#define TWI_SRX_GEN_DATA_NACK 0x98 // Previously addressed with general call; data has been received; NOT ACK has been returned
#define TWI_SRX_STOP_RESTART 0xA0 // A STOP condition or repeated START condition has been received while still addressed as Slave
// TWI Miscellaneous status codes
#define TWI_NO_STATE 0xF8 // No relevant state information available; TWINT = “0”
#define TWI_BUS_ERROR 0x00 // Bus error due to an illegal START or STOP condition
#endif
#endif
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 16.05.2007 by Dominik S. Herwald
*
* ************************************************** **************************
* Bugs, feedback, questions and modifications can be posted on the AREXX Forum
* on http://www.arexx.com/forum/ !
* Of course you can also write us an e-mail to: info@arexx.nl
* AREXX Engineering may publish updates from time to time on AREXX.com!
* ************************************************** **************************
* - LICENSE -
* GNU GPL v2 (http://www.gnu.org/licenses/gpl.txt, a local copy can be found
* on the RP6 CD in the RP6 sorce code folders!)
* This program is free software. You can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* ************************************************** **************************
*/
/************************************************** ***************************/
// EOF
und unsere RP6I2CmasterTWI.h (RP6Lib/RP6common/RP6I2CmasterTWI.h):
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> BASE CONTROLLER
* ----------------------------------------------------------------------------
* ------------------- [c]2006 / 2007 - AREXX ENGINEERING ---------------------
* -------------------------- http://www.arexx.com/ ---------------------------
* ************************************************** **************************
* File: RP6I2CmasterTWI.c
* Version: 1.0
* Target: RP6 Base & Processor Expansion - ATMEGA32 @8.00 or 16.00MHz
* Author(s): Dominik S. Herwald
* ************************************************** **************************
* Description:
* This is the I2C Bus Master Library.
*
* ************************************************** **************************
* CHANGELOG AND LICENSING INFORMATION CAN BE FOUND AT THE END OF THIS FILE!
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6I2CmasterTWI.h"
/*
* This function initializes the TWI interface! You need
* to call this first before you use the TWI interface!
* You should better use the macro I2CTWI_initMaster without __ at the
* beginning. There you can specify the SCL frequency in kHz!
* Example:
* I2CTWI_initMaster(100); // I2C Master mode with 100kHz SCL frequency
* // This calculates TWBR value automatically.
*
* __I2CTWI_initMaster(32); // I2C Master mode also with 100kHz SCL frequency
* // but directly calculated with the formula in the
* // MEGA32 datasheet.
*/
void __I2CTWI_initMaster(uint8_t twi_bitrate)
{
cli();
TWBR = twi_bitrate;
TWSR = 0x00; // DO NOT USE PRESCALER! Otherwise you need to mask the
TWDR = 0xFF; // TWSR Prescaler bits everywhere TWSR is read!
TWCR = (1<<TWEN);
TWI_statusReg.lastTransOK = 1;
sei();
}
/************************************************** ***************************/
// TWI Event handlers
// These functions are used to receive Data or react on errors.
void I2CTWI_requestedDataReady_DUMMY(uint8_t requestID){}
static void (*I2CTWI_requestedDataReadyHandler)(uint8_t) = I2CTWI_requestedDataReady_DUMMY;
void I2CTWI_setRequestedDataReadyHandler(void (*requestedDataReadyHandler)(uint8_t))
{
I2CTWI_requestedDataReadyHandler = requestedDataReadyHandler;
}
void I2CTWI_transmissionError_DUMMY(uint8_t requestID){}
static void (*I2CTWI_transmissionErrorHandler)(uint8_t) = I2CTWI_transmissionError_DUMMY;
void I2CTWI_setTransmissionErrorHandler(void (*transmissionErrorHandler)(uint8_t))
{
I2CTWI_transmissionErrorHandler = transmissionErrorHandler;
}
/************************************************** ***************************/
// Delay
/**
* A small delay that is required between some transfers. Without this delay
* the transmission may fail.
*/
void I2CTWI_delay(void)
{
volatile uint8_t dly = 150;
while(dly--);
}
/************************************************** ***************************/
// Control task
static uint8_t I2CTWI_buf[I2CTWI_BUFFER_SIZE];
static uint8_t I2CTWI_recbuf[I2CTWI_BUFFER_REC_SIZE];
static uint8_t TWI_msgSize;
volatile union TWI_statusReg TWI_statusReg = {0};
uint8_t TWI_TWSR_state = 0;
uint8_t I2CTWI_request_adr = 0;
uint8_t I2CTWI_request_reg = 0;
uint8_t I2CTWI_request_size = 0;
int16_t I2CTWI_requestID = 0;
uint8_t TWI_operation = I2CTWI_NO_OPERATION;
/**
* You have to call this functions frequently out of the
* main loop. It calls the event handlers above automatically if data has been received.
*/
void task_I2CTWI(void)
{
if (!I2CTWI_isBusy()) {
if (TWI_statusReg.lastTransOK) {
if(TWI_operation) {
if(TWI_operation == I2CTWI_SEND_REGISTER) {
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = I2CTWI_request_adr;
I2CTWI_buf[1] = I2CTWI_request_reg;
TWI_statusReg.all = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
TWI_operation = I2CTWI_REQUEST_BYTES;
}
else if (TWI_operation == I2CTWI_REQUEST_BYTES) {
I2CTWI_delay();
TWI_msgSize = I2CTWI_request_size + 1;
I2CTWI_request_adr = I2CTWI_request_adr | TWI_READ;
I2CTWI_buf[0] = I2CTWI_request_adr | TWI_READ;
TWI_statusReg.all = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
TWI_operation = I2CTWI_READ_BYTES_FROM_BUFFER;
}
else if (TWI_operation == I2CTWI_READ_BYTES_FROM_BUFFER) {
TWI_operation = I2CTWI_NO_OPERATION;
if(I2CTWI_requestID!=-1)
I2CTWI_requestedDataReadyHandler(I2CTWI_requestID) ;
}
}
}
else {
uint8_t errState = I2CTWI_getState();
if(errState != 0) {
TWI_operation = I2CTWI_NO_OPERATION;
TWI_statusReg.lastTransOK = 1;
I2CTWI_request_adr = 0;
I2CTWI_requestID = 0;
I2CTWI_request_size = 0;
I2CTWI_transmissionErrorHandler(errState);
}
}
}
}
/************************************************** ***************************/
// Request functions - you need to use requestedDataReadyHandler to receive
// the requested data...
/**
* Requests a number of Bytes from the target device. You need to set a requestID
* to be able to identify the request after the data has been received and the
* "requestedDataReady" event handler is called.
*/
void I2CTWI_requestDataFromDevice(uint8_t targetAdr, uint8_t requestID, uint8_t numberOfBytes)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
TWI_operation = I2CTWI_REQUEST_BYTES;
I2CTWI_request_adr = targetAdr;
I2CTWI_requestID = (int16_t)requestID;
I2CTWI_request_size = numberOfBytes;
}
/**
* Same as requestDataFromDevice, but this function first sets the register
* that has to be read and transmits the register number before!
* This is neccessary for the reaction on interrupt requests of slave devices as this
* function is non-blocking and thus very well suited for calls directly from ISRs.
*/
void I2CTWI_requestRegisterFromDevice(uint8_t targetAdr, uint8_t requestID, uint8_t reg, uint8_t numberOfBytes)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
TWI_operation = I2CTWI_SEND_REGISTER;
I2CTWI_requestID = (int16_t)requestID;
I2CTWI_request_adr = targetAdr;
I2CTWI_request_reg = reg;
I2CTWI_request_size = numberOfBytes;
}
/**
* This function can be used in the requestedDataReady Handler to get the
* received data from the TWI Buffer. You need to provide a pointer to a
* buffer which is large enough to hold all received data.
* You can specify the number of bytes you want to read out of the buffer
* with the msgSize parameter.
* It does not make sense to use this function anywhere else as you
* can not guarantee what is in the reception buffer...
*/
void I2CTWI_getReceivedData(uint8_t *msg, uint8_t msgSize)
{
while(I2CTWI_isBusy());
uint8_t i = 0;
if(TWI_statusReg.lastTransOK)
for(; i < msgSize; i++)
msg[i] = I2CTWI_recbuf[i+1];
}
/**
* This function returns the last TWI State / Error State. It waits until
* TWI Module has completed last operation!
*/
uint8_t I2CTWI_getState(void)
{
while(I2CTWI_isBusy()); // Wait until TWI has completed the transmission.
return (TWI_TWSR_state); // Return error state.
}
/************************************************** ***************************/
// Read functions:
/**
* Reads "numberOfBytes" from "targetAdr" Register "reg" into "messageBuffer".
* If the slave device supports auto increment, then it reads all subsequent registers of course!
*/
void I2CTWI_readRegisters(uint8_t targetAdr, uint8_t reg, uint8_t * messageBuffer, uint8_t numberOfBytes)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
TWI_operation = I2CTWI_SEND_REGISTER;
I2CTWI_request_adr = targetAdr;
I2CTWI_requestID = -1;
I2CTWI_request_reg = reg;
I2CTWI_request_size = numberOfBytes;
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
if (TWI_statusReg.lastTransOK)
I2CTWI_getReceivedData(&messageBuffer[0], numberOfBytes+1);
}
/**
* Same as readRegisters, but you need to make sure which register to read yourself - if there
* are any registers at all in your slave device.
*
*/
void I2CTWI_readBytes(uint8_t targetAdr, uint8_t * messageBuffer, uint8_t numberOfBytes)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_operation = I2CTWI_REQUEST_BYTES;
I2CTWI_request_adr = targetAdr;
I2CTWI_requestID = -1;
I2CTWI_request_size = numberOfBytes;
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
if (TWI_statusReg.lastTransOK)
I2CTWI_getReceivedData(&messageBuffer[0], numberOfBytes+1);
}
/**
* Reads a single byte from the slave device.
*/
uint8_t I2CTWI_readByte(uint8_t targetAdr)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_operation = I2CTWI_REQUEST_BYTES;
I2CTWI_request_adr = targetAdr;
I2CTWI_requestID = -1;
I2CTWI_request_size = 1;
while(TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
if (TWI_statusReg.lastTransOK)
return I2CTWI_recbuf[1];
else
return 0;
}
/************************************************** ***************************/
// Transmission functions
/**
* Transmits a single byte to a slave device. It waits until the last
* TWI operation is finished (it blocks the normal program flow!) but
* it does NOT wait until this transmission is finished!
* This allows you to perform other things while the transmission is
* in progress!
*/
void I2CTWI_transmitByte(uint8_t targetAdr, uint8_t data)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data;
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
//With Sending Repeated Start
void I2CTWI_transmitByte_RepeatedStart(uint8_t targetAdr, uint8_t data)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 2;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data;
TWI_statusReg.all = 0;
no_rep_start = 0;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
/**
* This is just the same as transmitByte, but you can pass 2 Bytes to
* this function which are then transferred.
*/
void I2CTWI_transmit2Bytes(uint8_t targetAdr, uint8_t data1, uint8_t data2)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 3;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data1;
I2CTWI_buf[2] = data2;
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
/**
* Transmits 3 Bytes to the slave.
*/
void I2CTWI_transmit3Bytes(uint8_t targetAdr, uint8_t data1, uint8_t data2, uint8_t data3)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 4;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data1;
I2CTWI_buf[2] = data2;
I2CTWI_buf[3] = data3;
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
/**
* Transmits 4 Bytes to the slave.
*/
void I2CTWI_transmit4Bytes(uint8_t targetAdr, uint8_t data1, uint8_t data2, uint8_t data3, uint8_t data4)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
TWI_msgSize = 5;
I2CTWI_buf[0] = targetAdr;
I2CTWI_buf[1] = data1;
I2CTWI_buf[2] = data2;
I2CTWI_buf[3] = data3;
I2CTWI_buf[4] = data4;
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
/**
* Transmits "numberOfBytes" Bytes to the Slave device. The Bytes need to be
* in the Buffer "msg". Otherwise it is just the same as the other transmit functions.
*/
void I2CTWI_transmitBytes(uint8_t targetAdr, uint8_t *msg, uint8_t numberOfBytes)
{
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
I2CTWI_delay();
numberOfBytes++;
TWI_msgSize = numberOfBytes;
I2CTWI_buf[0] = targetAdr;
uint8_t i = 0;
for(; i < numberOfBytes; i++)
I2CTWI_buf[i+1] = msg[i];
TWI_statusReg.all = 0;
no_rep_start = 1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO);
}
/************************************************** ***************************/
// ISR:
/*
* TWI ISR
*/
uint8_t no_rep_start; //Wird ein Repeated start vom Slave benötigt?
ISR (TWI_vect)
{
static uint8_t TWI_bufPos = 0;
switch (TWSR)
{
case TWI_START: // START has been transmitted
case TWI_REP_START: // Repeated START has been transmitted
no_rep_start = 1;
TWI_bufPos = 0; // Set buffer pointer to the TWI Address location
case TWI_MTX_ADR_ACK: // SLA+W has been transmitted and ACK received
case TWI_MTX_DATA_ACK: // Data byte has been transmitted and ACK received
if (TWI_bufPos < TWI_msgSize) {
TWDR = I2CTWI_buf[TWI_bufPos++];
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| //
(0<<TWWC); //
} else { // Send STOP after last byte
TWI_statusReg.lastTransOK = 1; // Set status bits to completed successfully.
if(no_rep_start == 1){
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(0<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
}
else{
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(0<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a REPEATED START condition.
(0<<TWWC); //
}
}
break;
case TWI_MRX_DATA_ACK: // Data byte has been received and ACK transmitted
I2CTWI_recbuf[TWI_bufPos++] = TWDR;
case TWI_MRX_ADR_ACK: // SLA+R has been transmitted and ACK received
if (TWI_bufPos < (TWI_msgSize-1) ) { // Detect the last byte to NACK it.
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after reception
(0<<TWWC); //
} else { // Send NACK after next reception
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send NACK after reception
(0<<TWWC); //
}
break;
case TWI_MRX_DATA_NACK: // Data byte has been received and NACK transmitted
I2CTWI_recbuf[TWI_bufPos] = TWDR;
TWI_statusReg.lastTransOK = 1; // Set status bits to completed successfully.
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC); //
break;
case TWI_ARB_LOST: // Arbitration lost
TWI_TWSR_state = TWSR; // Store TWSR
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a (RE)START condition.
(0<<TWWC); //
break;
default:
TWI_TWSR_state = TWSR; // Store TWSR
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins
(0<<TWIE)|(1<<TWINT)| // Disable Interupt
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // No Signal requests
(0<<TWWC);
break;
}
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 16.05.2007 by Dominik S. Herwald
*
* ************************************************** **************************
* Bugs, feedback, questions and modifications can be posted on the AREXX Forum
* on http://www.arexx.com/forum/ !
* Of course you can also write us an e-mail to: info@arexx.nl
* AREXX Engineering may publish updates from time to time on AREXX.com!
* ************************************************** **************************
* - LICENSE -
* GNU GPL v2 (http://www.gnu.org/licenses/gpl.txt, a local copy can be found
* on the RP6 CD in the RP6 sorce code folders!)
* This program is free software. You can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* ************************************************** **************************
*/
/************************************************** ***************************/
// EOF
Mehr ist, soweit ich weiß, nicht geändert.
Die Abfolge von Befehlen zum Abfragen der Werte aus dem Sensor kommt noch, da müssen wir noch etwas basteln (damit die Umrechnung in °C funktioniert).
Bei weiteren Fragen könnt ihr gerne diesen Thread weiterverwenden!
EDIT:
So könnt ihr den Sensor selbst abfragen. Ihr bekommt zum Schluss z.B. für 22,53°C den Wert 2253 (damit ihr nicht mit riesigen Variablen oder Floats arbeiten müsst):
int16_t getMLX90614(void)
{
I2CTWI_transmitByte_RepeatedStart(0x5A<<1,0x07);
I2CTWI_readBytes(0x5A<<1, sensorBuf, 3);
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempdata = (((sensorBuf[1] & 0x007F) << 8) + sensorBuf[0]);
tempdata = (tempdata * 2)-1;
tempdata = tempdata - 27315;
return tempdata;
}
teamohnename
03.03.2012, 11:32
Hallo,
es gibt ein neues Problem...
Viele move Funktionen funktionieren nicht mehr. Wir benötigen nur moveAtSpeed und stop, wobei moveAtSpeed teilweise funktioniert und stop gar nicht. Anscheinend hängt das Programm sich an den whiles und waitForTransmit Funktionen auf. Eventuell liegt das aber auch an den I2CTWI_transmitXBytes Funktionen. Kann man das irgendwie mit dem normalen I2CTWI_transmitByte lösen?
So langsam ist das alles echt zum Verzweifeln... Ein Problem nach dem anderen...
Vielen Dank für Eure Hilfe und
Viele Grüße
teamohnename
> So langsam ist das alles echt zum Verzweifeln... Ein Problem nach dem anderen...
Wenn man auf der low-level Ebene in der Lib was ändert kann das natürlich an anderer Stelle Probleme bereiten also soweit völlig normal ;)
--> Erstmal mit minimal Programm testen also nur initialisierung, pause, betroffene Funktionen aufrufen und endlosschleife.
Dann in die betroffenen Funktionen debug ausgaben rein machen (vermutlich schon passiert?)
Evtl. fehlt ja irgendwo das no_rep_start = 1 o.ä.
teamohnename
03.03.2012, 17:10
Haben wir alles schon gemacht.
Nur die Stop Funktion macht Probleme, von daher wird es wohl an dem waitForTransmit liegen...
Ist erstmal egal, es gibt ein noch viel größeres Problem: Wenn man in der Hauptschleife die Infrarotsensoren abfragt und moveAtSpeed benutzt, funktionieren die Infrarotsensoren nicht mehr. Das hat garantiert nichts damit zu tun, dass die Motoren an sind.
Vielleicht wäre es doch einfacher, komplett auf die Fleury Library umzusteigen...
EDIT:
So, mit der Library von Peter Fleury auf der M32 Platine und dem Slave Programm aus den RP6 Examples auf der Base funktioniert alles. Wir werden, sobald wir alles, was mit der neuen Library nicht benötigt wird, aus dem Programm entfernt haben, hier alles posten.
EDIT2:
So:
1) Im Makefile Zeile 74 (dort, wo die Standard I²C Library eingebunden wird) entfernen oder auskommentieren
2) Die I²C Master Library von Peter Fleury (http://homepage.hispeed.ch/peterfleury/avr-software.html#libs) herunterladen
3) Library (nur die Dateien twimaster.c und i2cmaster.h) in den Ordner einfügen, in den auch das Hauptprogramm und das Makefile ist
4) In twimaster.c I²C Geschwindigkeit und ggf. CPU Takt (16MHz, also 16000000Hz) festlegen
5) Ins Hauptprogramm zu den anderen includes schreiben:
#include "i2cmaster.h"
6) Ins Hauptprogramm die Zeilen
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
durch das:
i2c_init();
ersetzen.
7) Ggf. RP6Control_I2CMasterLib.c durch das ersetzen:
(ACHTUNG: move, rotate und setLEDs kann man dann nicht mehr benutzen, nur noch moveAtSpeed, changeDirection und stop. Natürlich kann man das alles ergänzen, wenn man will, wir benötigen das aber nicht, deshalb haben wir uns keine Arbeit damit gemacht)
// Includes:
#include "RP6Control_I2CMasterLib.h"
/************************************************** ***************************/
// Sensors/ADCs:
// ADCs:
uint16_t adcBat;
uint16_t adcMotorCurrentLeft;
uint16_t adcMotorCurrentRight;
uint16_t adcLSL;
uint16_t adcLSR;
uint16_t adc0;
uint16_t adc1;
//Accelerometer:
int16_t threedbs_x;
int16_t threedbs_y;
int16_t threedbs_z;
//IR (MLX90614)
int16_t mlx90614_l;
int16_t mlx90614_r;
// Measured Speed:
uint8_t mleft_speed;
uint8_t mright_speed;
// Distance
uint16_t mleft_dist;
uint16_t mright_dist;
// Desired Speed:
uint8_t mleft_des_speed;
uint8_t mright_des_speed;
// Power
uint8_t mleft_power;
uint8_t mright_power;
uint8_t sensorBuf[24];
/**
* In order to use the same register names as in the RP6Lib, this
* function reads all ADC channels and all motor parameters into
* the same values as in the RP6Lib.
* Of course this function needs some time to read all these
* 24 registers via the I2C Bus.
*/
void getAllSensors(void)
{
i2c_start(I2C_RP6_BASE_ADR+0);
i2c_write(I2C_REG_POWER_LEFT);
i2c_rep_start(I2C_RP6_BASE_ADR+1);
for(uint8_t i = 0; i<23; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[23] = i2c_readNak();
i2c_stop();
mleft_power = sensorBuf[0];
mright_power = sensorBuf[1];
mleft_speed = sensorBuf[2];
mright_speed = sensorBuf[3];
mleft_des_speed = sensorBuf[4];
mright_des_speed = sensorBuf[5];
mleft_dist = sensorBuf[6] + (sensorBuf[7]<<8);
mright_dist = sensorBuf[8] + (sensorBuf[9]<<8);
adcLSL = sensorBuf[10] + (sensorBuf[11]<<8);
adcLSR = sensorBuf[12] + (sensorBuf[13]<<8);
adcMotorCurrentLeft = sensorBuf[14] + (sensorBuf[15]<<8);
adcMotorCurrentRight = sensorBuf[16] + (sensorBuf[17]<<8);
adcBat = sensorBuf[18] + (sensorBuf[19]<<8);
adc0 = sensorBuf[20] + (sensorBuf[21]<<8);
adc1 = sensorBuf[22] + (sensorBuf[23]<<8);
}
/**
*
*/
void getLightSensors(void)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(I2C_REG_ADC_LSL_L);
i2c_rep_start(I2C_RP6_BASE_ADR+1);
for(uint8_t i = 0; i<3; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[3] = i2c_readNak();
i2c_stop();
adcLSL = sensorBuf[0] + (sensorBuf[1]<<8);
adcLSR = sensorBuf[2] + (sensorBuf[3]<<8);
}
/**
*
*/
void getADCs(void)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(I2C_REG_ADC_ADC0_L);
i2c_rep_start(I2C_RP6_BASE_ADR+1);
for(uint8_t i = 0; i<3; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[3] = i2c_readNak();
i2c_stop();
adc0 = sensorBuf[0] + (sensorBuf[1]<<8);
adc1 = sensorBuf[2] + (sensorBuf[3]<<8);
}
/**
*
*/
void get3DBS(void)
{
i2c_start(I2C_3DBS_ADR);
i2c_write(I2C_REG_3DBS);
i2c_rep_start(I2C_3DBS_ADR+1);
for(uint8_t i = 0; i<5; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[5] = i2c_readNak();
i2c_stop();
threedbs_x = sensorBuf[1];//i2c_readAck() + (i2c_readAck()<<8);
threedbs_y = sensorBuf[3];//i2c_readAck() + (i2c_readAck()<<8);
threedbs_z = sensorBuf[5];//i2c_readAck() + (i2c_readNak()<<8);
}
/*
*
*/
void getIR(void)
{
i2c_start_wait(I2C_MLX90614_L);
i2c_write(I2C_REG_MLX90614);
i2c_rep_start((I2C_MLX90614_L)+1);
for(uint8_t i = 0; i<2; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[2] = i2c_readNak();
i2c_stop();
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
int16_t tempdata = (((sensorBuf[1] & 0x007F) << 8) + sensorBuf[0]);
tempdata = (tempdata * 2)-1;
mlx90614_l = tempdata - 27315;
i2c_start_wait(I2C_MLX90614_R);
i2c_write(I2C_REG_MLX90614);
i2c_rep_start((I2C_MLX90614_R)+1);
for(uint8_t i = 0; i<2; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[2] = i2c_readNak();
i2c_stop();
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempdata = (((sensorBuf[1] & 0x007F) << 8) + sensorBuf[0]);
tempdata = (tempdata * 2)-1;
mlx90614_r = tempdata - 27315;
}
/*
*
*/
void getDists(void)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(I2C_REG_DIST_LEFT_L);
i2c_rep_start(I2C_RP6_BASE_ADR+1);
for(uint8_t i = 0; i<3; i++)
{
sensorBuf[i] = i2c_readAck();
}
sensorBuf[3] = i2c_readNak();
i2c_stop();
mleft_dist = sensorBuf[0] + (sensorBuf[1]<<8);
mright_dist = sensorBuf[2] + (sensorBuf[3]<<8);
}
/************************************************** ***************************/
/************************************************** ***************************/
// Movement functions:
/**
* Move at speed function - just the same as with RP6Lib!
*/
void moveAtSpeed(uint8_t desired_speed_left, uint8_t desired_speed_right)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(0);
i2c_write(CMD_MOVE_AT_SPEED);
i2c_write(desired_speed_left);
i2c_write(desired_speed_right);
i2c_stop();
}
/**
* Change direction function - just the same as with RP6Lib!
*/
void changeDirection(uint8_t dir)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(0);
i2c_write(CMD_CHANGE_DIR);
i2c_write(dir);
i2c_stop();
}
/**
* Stop function - just the same as with RP6Lib!
*/
void stop(void)
{
i2c_start_wait(I2C_RP6_BASE_ADR);
i2c_write(0);
i2c_write(CMD_STOP);
i2c_stop();
}
und RP6Control_I2CMasterLib.h durch das ersetzen:
#ifndef RP6CONTROL_I2CMASTERLIB_H
#define RP6CONTROL_I2CMASTERLIB_H
/************************************************** ***************************/
// Includes:
#include "RP6ControlLib.h"
// define the RP6 Base address here:
#define I2C_RP6_BASE_ADR 10
//other I2C adresses:
#define I2C_3DBS_ADR 0x70
#define I2C_MLX90614_L 0x55<<1
#define I2C_MLX90614_R 0x5A<<1
/************************************************** ***************************/
// These are the same command definitions as you can find them in the
// I2C Bus Slave Example program for RP6Base:
#define I2C_REG_STATUS1 0
#define I2C_REG_STATUS2 1
#define I2C_REG_MOTION_STATUS 2
#define I2C_REG_POWER_LEFT 3
#define I2C_REG_POWER_RIGHT 4
#define I2C_REG_SPEED_LEFT 5
#define I2C_REG_DES_SPEED_LEFT 7
#define I2C_REG_DES_SPEED_RIGHT 8
#define I2C_REG_DIST_LEFT_L 9
#define I2C_REG_DIST_LEFT_H 10
#define I2C_REG_DIST_RIGHT_L 11
#define I2C_REG_DIST_RIGHT_H 12
#define I2C_REG_ADC_LSL_L 13
#define I2C_REG_ADC_LSL_H 14
#define I2C_REG_ADC_LSR_L 15
#define I2C_REG_ADC_LSR_H 16
#define I2C_REG_ADC_MOTOR_CURL_L 17
#define I2C_REG_ADC_MOTOR_CURL_H 18
#define I2C_REG_ADC_MOTOR_CURR_L 19
#define I2C_REG_ADC_MOTOR_CURR_H 20
#define I2C_REG_ADC_UBAT_L 21
#define I2C_REG_ADC_UBAT_H 22
#define I2C_REG_ADC_ADC0_L 23
#define I2C_REG_ADC_ADC0_H 24
#define I2C_REG_ADC_ADC1_L 25
#define I2C_REG_ADC_ADC1_H 26
#define I2C_REG_RC5_ADR 27
#define I2C_REG_RC5_DATA 28
#define I2C_REG_LEDS 29
//Commands od other I2C devices:
#define I2C_REG_3DBS 0x02
#define I2C_REG_MLX90614 0x07
#define CMD_POWER_OFF 0
#define CMD_POWER_ON 1
#define CMD_CONFIG 2
#define CMD_SETLEDS 3
#define CMD_STOP 4
#define CMD_MOVE_AT_SPEED 5
#define CMD_CHANGE_DIR 6
#define CMD_MOVE 7
#define CMD_ROTATE 8
#define CMD_SET_ACS_POWER 9
#define CMD_SEND_RC5 10
#define CMD_SET_WDT 11
#define CMD_SET_WDT_RQ 12
/************************************************** ***************************/
#define getMotorRight() (OCR1A)
#define getMotorLeft() (OCR1B)
//Encoders:
extern uint8_t mleft_speed;
extern uint8_t mright_speed;
// Distance
extern uint16_t mleft_dist;
extern uint16_t mright_dist;
// Desired Speed:
extern uint8_t mleft_des_speed;
extern uint8_t mright_des_speed;
// Power
extern uint8_t mleft_power;
extern uint8_t mright_power;
#define getLeftSpeed() (mleft_speed)
#define getRightSpeed() (mright_speed)
#define getLeftDistance() (mleft_dist)
#define getRightDistance() (mright_dist)
#define getDesSpeedLeft() (mleft_des_speed)
#define getDesSpeedRight() (mright_des_speed)
//Direction:
#define FWD 0
#define BWD 1
#define LEFT 2
#define RIGHT 3
#define getDirection() (drive_status.direction)
#define INT0_STATUS_CHECK 0
/************************************************** ***************************/
//
void initI2C_RP6Lib(void);
uint8_t checkRP6Status(uint8_t dataRequestID);
void I2C_transmissionError(uint8_t errorState);
void task_checkINT0(void);
#define NON_BLOCKING 0
#define BLOCKING 1
void rotate(uint8_t desired_speed, uint8_t dir, uint16_t angle, uint8_t blocking);
void move(uint8_t desired_speed, uint8_t dir, uint16_t distance, uint8_t blocking);
void moveAtSpeed(uint8_t desired_speed_left, uint8_t desired_speed_right);
void changeDirection(uint8_t dir);
void stop(void);
void getADCs(void);
void getDists(void);
void get3DBS(void);
void getIR(void);
#define isMovementComplete() (drive_status.movementComplete)
extern uint8_t bumper_left;
extern uint8_t bumper_right;
extern uint8_t obstacle_left;
extern uint8_t obstacle_right;
#define isObstacleLeft() (obstacle_left)
#define isObstacleRight() (obstacle_right)
extern uint16_t adcBat;
extern uint16_t adcMotorCurrentLeft;
extern uint16_t adcMotorCurrentRight;
extern uint16_t adcLSL;
extern uint16_t adcLSR;
extern uint16_t adc0;
extern uint16_t adc1;
//Accelerometer:
extern int16_t threedbs_x;
extern int16_t threedbs_y;
extern int16_t threedbs_z;
//IR (MLX90614)
extern int16_t mlx90614_l;
extern int16_t mlx90614_r;
#define TOGGLEBIT 32
typedef union {
uint16_t data;
struct {
uint8_t key_code:6;
uint8_t device:5;
uint8_t toggle_bit:1;
uint8_t reserved:3;
};
} RC5data_t;
void IRCOMM_sendRC5(uint8_t adr, uint8_t data);
void IRCOMM_setRC5DataReadyHandler(void (*rc5Handler)(RC5data_t));
void ACS_setStateChangedHandler(void (*acsHandler)(void));
void MOTIONCONTROL_setStateChangedHandler(void (*motionControlHandler)(void));
void BUMPERS_setStateChangedHandler(void (*bumperHandler)(void));
void WDT_setRequestHandler(void (*requestHandler)(void));
void getAllSensors(void);
void getLightSensors(void);
#endif
nun sollte alles funktionieren. Bei Fragen einfach fragen! ;)
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.