PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C Funktioniert nicht mit Atmega8



semicolon
17.01.2007, 15:11
Hallo

Mein I2C Bus tut nicht so wie er sollte. Hardwaremässig sollte alles I.o. sein. Habe die beiden Leitungen SDA/SCL via je 10kOhm Widerstände gegen 1% Volt gezogen. Meinen I2C Bus benötige ich um meine RTC PCF8583 zu steuern.

Aber da will überhaupt nichts gehen.


Hier mein Code:
/************************************************** ********
Function: Initialisiert die I2C Schnittstelle:
- TWI enable
- Baud-Rate: 25kHz
Input: NOP
Output: NOP
************************************************** ********/
void init_I2C(void)
{

TWBR = 12; //Baud-Rate
TWSR = 0; /* no prescaler */

}

/************************************************** ********
Function: wait for TWINT Flag set. This indicates that
the START condition has been transmitted
Input: NOP
Output: NOP
************************************************** ********/
void wait_for_ACK(void)
{
while (!(TWCR & (1<<TWINT)));
}

/************************************************** ********
Function: Send one byte to I2C device

Input: byte to be transfered
Output: 0 write successful
1 write failed
************************************************** *********/
unsigned char i2c_write( unsigned char data )
{
uint8_t twst;

// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed
wait_for_ACK();

// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;

return 0;
}

/************************************************** ***********************
Function: Terminates the data transfer and releases the I2C bus

Input: NOP
Output: NOP
************************************************** ***********************/
void i2c_stop(void)
{
/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released
wait_for_ACK();

}/* i2c_stop */

/************************************************** **************************************
Function: Issues a start condition and sends address and transfer direction.

Input: Device Address + Direction
Output: return 0 = device accessible,
1= failed to access device
************************************************** **************************************/
unsigned char i2c_start(unsigned char address)
{
uint8_t twst;

// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed
wait_for_ACK();

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed and ACK/NACK has been received
wait_for_ACK();

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;

if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

return 0;

}/* i2c_start */

Was ist an meiner Software falsch? Wie kann ich mit dem Osziloskop überprüfen ob mein I2C Bus funktioniert? Als vielleicht über den SCL Pin
Wie muss ich die Datenrichtungsregister für den Atmega8 konfigurieren wenn ich den I2C benutze?

Danke.

linux_80
17.01.2007, 20:10
Hallo,
wenn Du TWI benutzt, musst Du dich nicht um die Richtungsregister kümmern, das TWI-Modul macht das alles selber.

Damit der Leitungspegel passt, muss das TWI-Modul immer in einem bestimmten Status sein, bzw. auf die richtige Aktion reagieren damit es weitergeht, und der AVR nicht den Bus blockiert.

Wenn Du was messen willst,
wenn nix los ist, müssen beide Leitungen high sein, wenn Daten übertragen werden kann man auf der Taktleitung SCL alle Bits incl. ACK/NACK rauszählen, also 9 Takte pro Byte. Auf der Datenleitung sieht man das entsprechende Datenbyte, wenn mehrere 0-Bits kommen, ist die Leitung eben solange low.

semicolon
17.01.2007, 21:05
Ok ich habe das heute Abend noch kurz überprüft und wenn nichts läuft, so scheint es, sind sowohl SCL und SDA beide auf Hight. Vielleicht muss ich mal eine Datenübertragung mittels Logic Analyser messen.

Dann kann ich wahrscheinlich davon ausgehen, dass mein I2C Bus also funktioniert. Hast du keine Fehler in meinem Code entdeckt?

Dann habe ich aber noch mein Problemchen mit der RTC.

Wenn ich nun etwas auf die RTC schreiben will mache ich das folgendermassen:

i2c_start(RTC_sla_addr+I2C_Write);
i2c_write(Alarm_Control_Register_addr);
i2c_write(0x4A);
i2c_stop();

wobei RTC_sla_addr die Adresse des RTC ist.

Oder sitmmt hier noch etwas nicht?

Vielen Dank!!!

linux_80
17.01.2007, 22:40
Vom Prinzip her sollte es gehen, Du hast aber keine Funktion um vom Slave zu lesen !
Beim InitI2C sollte TWI schon mal aktiviert werden, sonst kann's evtl. passieren, das der Pegel rauf- oder runtergezogen wird, was sich aber nur negativ auswirkt, wenns mehr als einen Master gibt.

Bei einem Fehler nicht einfach die Funktion mit return verlassen, sondern das TWI-Modul in einen definierten Zustand bringen, auch wenn ein Start nicht geklappt hat, muss man irgendwelche Flags setzen damit der Bus nicht blockiert wird.

Du kannst das Prinzip aber auch mit dem Bascom Programm vergleichen aus dem Wiki (-> TWI-Praxis).
Man kann auch auf diversen Seiten abschauen wie zB.
http://www.nongnu.org/avr-libc/user-manual/group__twi__demo.html

semicolon
18.01.2007, 10:52
Das hat eigentlich einen simplen Grund, da ich die RTC nur als Timer verwene brauche ich nichts zu lesen. Vielleicht muss ich diese Methode aber no regänzen damit ich besser debuggen kann.

Wie meinst du das mit einen definierten Zustand bringen? Wahrscheinlich ist es schon so, dass mein Bus blockiert ist, weil etwas schief gegangen ist bei der Übertragung.

Sonst weiss ich nichts mehr, was falsch ist.

linux_80
20.01.2007, 13:58
Auch wenn ein Fehler aufgetreten ist, muss man dem TWI sagen wie es weitergeht, bzw. man setzt es zurück, sonst klappt auch nicht nächste Sendung (Startsequenz) nicht.
Auch wenn Du in C progst, kannst Du an den Bascom-Beipielen erkennen wie man der Reihe nach die Aktionen ausführen muss, um evtl. Fehler abzufangen. Und wie man das TWI danach wieder in Ausgangsstellung bringt.

semicolon
22.01.2007, 09:28
Ok habe jetzt mein System, wenns nicht klappen sollte, in einen definierten Zusatnd gebracht. Jedenfalls läuft es jetzt einwandfrei. Irgendwie war es aber trotzdem komisch das es vorher nicht ging. So viel habe ich nicht geändert.