Frage zu RP6 I2C Library: Funktionen der Lib von Peter Fleury?
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):
Code:
[...]
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?
Code:
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
Liste der Anhänge anzeigen (Anzahl: 3)
*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.
Anhang 21590Anhang 21591Anhang 21592
EDIT2:
gerade hier gelesen:
Zitat:
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:
Zitat:
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
Liste der Anhänge anzeigen (Anzahl: 3)
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:
Code:
I2CTWI_readRegisters(0x5A<<1,0x07, sensorBuf, 3);
Code:
//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:
Anhang 21601Anhang 21602Anhang 21603
Vielen, vielen Dank für Eure Hilfe und
Viele Grüße
teamohnename
Liste der Anhänge anzeigen (Anzahl: 4)
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
Anhang 21615Anhang 21616Anhang 21617Anhang 21618
Liste der Anhänge anzeigen (Anzahl: 1)
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:
Anhang 21622
Liste der Anhänge anzeigen (Anzahl: 1)
Das sieht auf dem Oszi jetzt mit dem Code:
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:
Anhang 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.
Code:
//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.
Code:
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:
Code:
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:
Code:
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:
Code:
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:
Code:
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?
Liste der Anhänge anzeigen (Anzahl: 2)
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:
Code:
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
zu dem:
Code:
TWCR = (1<<TWEN)|(1<<TWIE)|(0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO);
ändert, können wir damit:
Code:
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
und damit (bewirkt das gleiche):
Code:
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:
Code:
I2CTWI_transmitByte_RepeatedStart(0x55<<1,0x07);
uint8_t irmsb = I2CTWI_readByte(0x55<<1);
uint8_t irlsb = I2CTWI_readByte(0x55<<1);
und hiermit:
Code:
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.
Anhang 21637Anhang 21638