PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C-Probs



TobeFFM
16.11.2008, 19:53
Hi Leute!
Ich hab mir mit nem Atmega8 ne kleine Erweiterung gebaut. Da hängt ein LCD dran, und ich will von der Base Nachrichten hinschicken, die dann auf dem LCD ausgegeben werden.
Ich hab den TWI-Master-Code und header im Base-Projekt eingebunden, und den TWI-Slave-Code und header in meinen Code und Makefile für den Atmega8.
Ich habe mal testweise im Atmega8 readRegisters mit Werten befüllt, und kann diese auch erfolgreich von der Base auslesen. Nur, wenn ich versuche von der Base was in die writeRegisters zu schreiben, kommt dort anscheinend nichts an (Funktion aus Anleitung: transmit3Bytes(SlaveAddr, Reg#, data1, data2).

Hier ist der Code, der auf der Base läuft (abgespeckt, da läuft noch Example07, die State-Machine drauf):


#include "RP6RobotBaseLib.h"

#include "RP6I2CmasterTWI.h"


void I2C_transmissionError(uint8_t errorState)

{

writeString_P("\nI2C ERROR - TWI STATE: 0x");

writeInteger(errorState, HEX);

writeChar('\n');

}


int main(void)

{

initRobotBase();
// I2C Master initialisieren

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

powerON();

while(true)

{

// versuche, was zu schreiben
I2CTWI_transmit3Bytes(15, 0, 1, 3);

//versuchen was zu lesen, Register 0-3:
//I2CTWI_transmitByte(15, 0);
uint8_t results[ 4];
I2CTWI_readBytes(15, results, 3);
writeString_P("\n Empfangen (0-3): ");
for(int i=0; i<3; i++){
writeInteger(results[i], DEC);
writeString_P(" - ");
}
writeString_P("\n");

}

return 0;

}


Und hier der Code der Atmega8-LCD-Erweiterungsplatine:


#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
#include "General.h"
#include "Delay.h"
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd-routines.h"
#include "RP6I2CslaveTWI.h"

#define CMD_ZEILE_1 1
#define CMD_ZEILE_2 2

int main(void)
{
// LCD-INIT -----------------------------------
lcd_init();
lcd_string("RP6 Robo-LCD");
Delay_ms(2500);

// I2C-INIT -----------------------------------
I2CTWI_initSlave(15); // Wir haben Adresse 15!
set_cursor(0,1);
lcd_clear();
lcd_string("Waiting.....");

// MAIN-LOOP ----------------------------------
while(1)
{

// schreib mal irgendwas ins register, was ausgelesen wird
I2CTWI_readRegisters[0] = 5;
I2CTWI_readRegisters[1] = 8;
I2CTWI_readRegisters[2] = 7;


// empfangen und kein Schreibzugriff aktiv
if(I2CTWI_writeRegisters[0]!='_' && !I2CTWI_writeBusy){
// TEST
lcd_clear();
set_cursor(0,2);
lcd_string("Innere Schleife");

// speichern
char buffer[20];
uint8_t cmd = I2CTWI_writeRegisters[0];
I2CTWI_writeRegisters[0] = 0; //zurücksetzen
uint8_t param = I2CTWI_writeRegisters[1]; //Parameter
if(cmd == CMD_ZEILE_1){
lcd_clear();
set_cursor(0,1);
lcd_string("CMD Zeile 1");
Delay_ms(2500);
lcd_clear();
set_cursor(0,1);
itoa(param, buffer, 10);
lcd_string(buffer);
}else if(cmd == CMD_ZEILE_2){
set_cursor(0,2);
itoa(param, buffer, 10);
lcd_string(buffer);
}
}


}//while(1)
return 0;
}


Wie gesagt, Register werden erfolgreich ausgelesen, also ist die Verkabelung korrekt. Ich häng da jetzt seit fast zwei Tagen dran und bin kurz vorm durchdrehn, weil ichs einfach nich versteh :-)

radbruch
16.11.2008, 20:18
Um es gleich vorweg zu sagen: Ich bin I2C-Laie.

Zum TWI-Master: Muss nicht die Schreib- und Leseadresse unterschiedlich sein? LesenAdr ist SchreibenAdr+1?

So war das zumindest beim Nunchuck (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=390124#390124).

TobeFFM
16.11.2008, 20:55
ich glaube nicht...also jedenfalls steht dazu in den beispielen und der anleitung nichts, dort wird immer die gleiche adresse für den slave verwendet, egal ob geschrieben oder gelesen wird..
Beim Lesen soll man erstmal ein Byte mit dem gewünschten Register schicken, dann auslesen.
Und fürs Schreiben (wenn ich das richtig verstanden habe) an die gleiche Adresse, und zwar 3 Byte (für das slave-example), nämlich Registernummer und zwei Werte für zwei Register..
was sein könnte, wäre, dass der I2C-Code ohne die RP6Lib nicht funktioniert, aber dann müsste es ja fehler beim compile geben..?
Wie gesagt hab ich beim Atmega8 die RP6I2Cslave.h eingebunden und im Makefile die RP6I2Cslave.c..

linux_80
16.11.2008, 21:11
Mit den I2C-Adresse hat man das Problem, das die einen von 7 Bit, die anderen von 8Bit Adresse ausgehen.
Je nach Lib wird das RW-Bit intern gesetzt, je nach Modus. Wenn man die Bytes selber auf den Bus schiebt, muss man das RW auch selber behandeln, dann kommt die +1 ins Spiel.

Offiziell ist die Adresse nur, die oberen, 7 Bit.

radbruch
16.11.2008, 21:17
Da beide Kontroller die RP6-TWILib vervenden sollten die Adressen ja passen. Noch ein weiterer Versuch ohne mich in die Untiefen der TWI-Lib des RP6 zu stürtzen:

In den TWIMaster-Beispielen vom RB6 findet man in der Hauptschleife noch diesen Aufruf:

task_I2CTWI(); // Call I2C Management routine

Sind die TWI-Routinen als Task organisiert? Zumindest wenn man die Handler verwendet könnte das so sein.

TobeFFM
16.11.2008, 21:25
ich hatte das task_I2CTWI() schon im programm stehen, aber laut Anleitung wird das nur gebraucht, wenn man Register "im Hintergrund" auslesen will, also nicht-blockierendes Lesen, und nur Lesen..
Ja, die Libs sind beide die vom RP6, also sollte es nicht an den Adressen liegen...

TobeFFM
18.11.2008, 01:20
Hat noch keiner wirklich was damit gemacht, oder nur nicht mit dem Atmega8? Also, die readRegisters kann ich auslesen, auch auf einen general Call reagiert der Atmega.
Wie funktioniert das eigentlich mit dem general Call? Das ist eine Nachricht, die an Adresse 0 adressiert wird, das ist mir schon klar, aber wie wurde das implementiert? Die Anleitung is hier mehr als schwammig...
"die Variable I2C_genCALL enthält das zuletzt gesendete Commando.." Hä?! Was für einen Datentyp hat diese Variable? Wenn ich nen General Call mit transmit2Bytes(0, 0, 'x') absetze, kann ich auf dem Atmega das x auslesen. Aber das ist doch kein commando?! Kann man da nicht mehr Zeichen rausschicken, und die dann auch entsprechend vom Slave auswerten lassen?
Beim Versuch von buffer[i] = I2C_genCall[i] kam nur der Fehler, dass es sich bei I2C_genCall wohl nicht um ein array handelt...

Und das Problem mit der "richtigen" schreibe, also direkt in die writeRegisters vom Slave zu schreiben ist auch noch nicht gelöst, nichtmal annähernd, da geht nämlich gaaar nix (Code aus dem Beispiel genommen!!!)

Ich hab mal versucht, den TWI-Code von Mikrocontroller.net zu benutzen, was auch super funktioniert hat, nur blöderweise hats jedesmal mein Programm blockiert :-) Kurz: I2C funktioniert also, nur der Beispielcode nicht...

SlyD
18.11.2008, 11:18
Hallo,

Ich hab Dir gerade auch im AREXX Forum geantwortet.

Probiers mal mit ner geraden Adresse (z.B. 14)
;)

Bei den RP6Libs wird immer das gesamte 8Bit Adressbyte übergeben. Das unterste Bit muss frei bleiben - nur die oberen 7 sind die eigentliche Adresse.

MfG,
SlyD

TobeFFM
18.11.2008, 12:28
arrrrrrrgh... DANKE SLYD !!!
hehe, des könnt ruhig irgendwo stehen, ich hab mir richtig gut den Kopf zerbrochen :-) danke, jetzt gehts!

SlyD
18.11.2008, 13:42
Naja in den Beispielprogrammen wird überall ne gerade Adresse verwendet ;)

Aber Du hast natürlich recht, das wird noch in die nächste Version der Doku mit aufgenommen.

MfG,
SlyD