ikarus_177
08.08.2009, 13:18
Hallo allerseits und einen schönen Samstag,
ich möchte gerne etwa 8 Controller an ein TWI/I²C - Bussystem hängen, um Daten zwischen denselben austauschen zu können. Vorerst - zu Testzwecken und Einarbeitung - habe ich den Aufbau auf 2 Controller reduziert. Ein RN-Control und ein Mega32 auf einem Steckbrett sollen miteinandern ins Gespräch kommen. Ich habe SCL und SDA der beiden µC's verbunden und mit 10k Pull-Up-Widerständen versehen. Die Leitungslänge des Busses beträgt etwas mehr als 40cm.
Nun habe ich mich im Wiki schlau gemacht, welche Register usw. man braucht, um die nötigen Einstellungen vorzunehmen. Hier (http://rn-wissen.de/index.php/TWI) findet man ja eine sehr schöne Zusammenstellung. Bei der Umsetzung in C habe ich mich an diesen (http://rn-wissen.de/index.php/TWI_Praxis) Programmbeispielen, am Datenblatt sowie an den ApplicationNotes 311 (http://www.atmel.com/dyn/resources/prod_documents/doc2565.pdf) und 315 (http://www.atmel.com/dyn/resources/prod_documents/doc2564.pdf) orientiert und mal einige Zeilen Code geschrieben.
Leider gibts noch irgendwo einen Haken, den ich bis jetzt nicht entdecken konnte. Es scheint (für mich) so, als würde der Slave zwar angesprochen werden (kurzes Aufblitzen der LEDs an den Busleitungen), aber keine sinnvollen Daten empfangen können. Zu Testzwecken habe ich mir das empfangene Byte an einem Port ausgeben lassen, an dem ich aber stets den Wert Null messe. Nach stundenlangem Ausprobieren, kontrollieren und ausbessern kann ich keine Fehler mehr entdecken. Aber meist ist es ja so, dass einem die eigenen Fehler am wenigsten auffallen, und drum möchte ich euch bitten, vielleicht mal einen kurzen Blick auf meinen Code zu werfen, vielleicht fällt euch ja was auf.
Hier die Zeilen für den Master:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/twi.h>
void i2c_init (void);
uint8_t i2c_sendbyte (uint8_t Adress, uint8_t Data);
uint8_t i2c_status (void);
volatile uint8_t TWIStatus = 0;
int main (void)
{
DDRD = 0xFF;
uint8_t Status = 0;
i2c_init();
Status = i2c_sendbyte (26,15);
PORTD = Status; //Ausgabe des Status zu Debugzwecken
while(1);
return(0);
}
void i2c_init (void)
{
//Einstellen des Bustaktes auf 400kHz:
TWSR = 0;
TWBR = 12;
}
uint8_t i2c_sendbyte (uint8_t Adress, uint8_t Data)
{
uint8_t TWIStatus = 0; //Variable für Fehlercode
//Senden der Startbedingung und zurücksetzen des Flags:
TWCR = (1 << TWSTA) | (1 << TWINT) | (1 << TWEN);
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
/* -------------------------------------------------------------------------- */
/* Falls der Bus nicht gerade als "busy" gesetzt ist, wurde das TWI-Interrupt */
/* Bit gesetzt, der Statuswert kann nun ausgelesen werden. */
/* Ist kein Fehler aufgetreten, kann die Adresse mit gesetztem Write-Bit */
/* ausgegeben werden. */
/* -------------------------------------------------------------------------- */
if ((TWIStatus == 0x08) || (TWIStatus == 0x10))
{
//Zugriff auf Bus erlaubt, nun wird die Slaveadresse mit gesetztem Write-Bit ausgegeben:
TWDR = (Adress << 1) & 0xFE;
TWCR = (1 << TWINT) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
if ((TWIStatus == 0x18) || (TWIStatus == 0x20))
{
//Slaveadresse wurde erfolgreich gesendet, nun können Daten verschickt werden:
TWDR = Data;
TWCR = (1 << TWINT) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
if ((TWIStatus == 0x28) || (TWIStatus == 0x30))
{
TWIStatus = 0; //kein Fehler
}
}
}
//Senden der Stoppbedingung:
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return(TWIStatus);
}
uint8_t i2c_status()
{
//Warten, bis das Interrupt-Bit gesetzt und so das erfolgreiche Ende einer Busaktion angekündigt wurde
while(!(TWCR & (1 << TWINT)));
//Ausmaskieren der Prescaler-Bits und Rückgabe des Statuswertes
return(TWSR & 0xF8);
}
... und für den Slave:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/twi.h>
uint8_t i2c_getbyte(void);
void i2c_init(uint8_t Adress);
uint8_t i2c_status(void);
int main (void)
{
DDRD = 0xFF;
uint8_t buffer = 0;
i2c_init(26);
buffer = i2c_getbyte(); //Empfangen des Bytes
PORTD = buffer; //Ausgabe zur Kontrolle
while(1);
return(0);
}
void i2c_init(uint8_t Adress)
{
TWSR = 0;
TWAR = (Adress << 1);
TWCR = (1 << TWEA) | (1 << TWEN);
TWDR = 0xFF;
}
uint8_t i2c_getbyte(void)
{
uint8_t Status = 0;
uint8_t Byte = 0;
//Warten, bis der Slave angesprochen wurde
Status = i2c_status();
Byte = Status;
TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
return(Byte);
}
uint8_t i2c_status()
{
//Warten, bis das Interrupt-Bit gesetzt und so das erfolgreiche Ende einer Busaktion angekündigt wurde
while(!(TWCR & (1 << TWINT)));
//Ausmaskieren der Prescaler-Bits und Rückgabe des Statuswertes
return(TWSR & 0xF8);
}
Herzlichen Dank fürs Lesen; vielleicht hat ja einer eine Idee.
Schönes Wochenende,
ikarus_177
ich möchte gerne etwa 8 Controller an ein TWI/I²C - Bussystem hängen, um Daten zwischen denselben austauschen zu können. Vorerst - zu Testzwecken und Einarbeitung - habe ich den Aufbau auf 2 Controller reduziert. Ein RN-Control und ein Mega32 auf einem Steckbrett sollen miteinandern ins Gespräch kommen. Ich habe SCL und SDA der beiden µC's verbunden und mit 10k Pull-Up-Widerständen versehen. Die Leitungslänge des Busses beträgt etwas mehr als 40cm.
Nun habe ich mich im Wiki schlau gemacht, welche Register usw. man braucht, um die nötigen Einstellungen vorzunehmen. Hier (http://rn-wissen.de/index.php/TWI) findet man ja eine sehr schöne Zusammenstellung. Bei der Umsetzung in C habe ich mich an diesen (http://rn-wissen.de/index.php/TWI_Praxis) Programmbeispielen, am Datenblatt sowie an den ApplicationNotes 311 (http://www.atmel.com/dyn/resources/prod_documents/doc2565.pdf) und 315 (http://www.atmel.com/dyn/resources/prod_documents/doc2564.pdf) orientiert und mal einige Zeilen Code geschrieben.
Leider gibts noch irgendwo einen Haken, den ich bis jetzt nicht entdecken konnte. Es scheint (für mich) so, als würde der Slave zwar angesprochen werden (kurzes Aufblitzen der LEDs an den Busleitungen), aber keine sinnvollen Daten empfangen können. Zu Testzwecken habe ich mir das empfangene Byte an einem Port ausgeben lassen, an dem ich aber stets den Wert Null messe. Nach stundenlangem Ausprobieren, kontrollieren und ausbessern kann ich keine Fehler mehr entdecken. Aber meist ist es ja so, dass einem die eigenen Fehler am wenigsten auffallen, und drum möchte ich euch bitten, vielleicht mal einen kurzen Blick auf meinen Code zu werfen, vielleicht fällt euch ja was auf.
Hier die Zeilen für den Master:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/twi.h>
void i2c_init (void);
uint8_t i2c_sendbyte (uint8_t Adress, uint8_t Data);
uint8_t i2c_status (void);
volatile uint8_t TWIStatus = 0;
int main (void)
{
DDRD = 0xFF;
uint8_t Status = 0;
i2c_init();
Status = i2c_sendbyte (26,15);
PORTD = Status; //Ausgabe des Status zu Debugzwecken
while(1);
return(0);
}
void i2c_init (void)
{
//Einstellen des Bustaktes auf 400kHz:
TWSR = 0;
TWBR = 12;
}
uint8_t i2c_sendbyte (uint8_t Adress, uint8_t Data)
{
uint8_t TWIStatus = 0; //Variable für Fehlercode
//Senden der Startbedingung und zurücksetzen des Flags:
TWCR = (1 << TWSTA) | (1 << TWINT) | (1 << TWEN);
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
/* -------------------------------------------------------------------------- */
/* Falls der Bus nicht gerade als "busy" gesetzt ist, wurde das TWI-Interrupt */
/* Bit gesetzt, der Statuswert kann nun ausgelesen werden. */
/* Ist kein Fehler aufgetreten, kann die Adresse mit gesetztem Write-Bit */
/* ausgegeben werden. */
/* -------------------------------------------------------------------------- */
if ((TWIStatus == 0x08) || (TWIStatus == 0x10))
{
//Zugriff auf Bus erlaubt, nun wird die Slaveadresse mit gesetztem Write-Bit ausgegeben:
TWDR = (Adress << 1) & 0xFE;
TWCR = (1 << TWINT) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
if ((TWIStatus == 0x18) || (TWIStatus == 0x20))
{
//Slaveadresse wurde erfolgreich gesendet, nun können Daten verschickt werden:
TWDR = Data;
TWCR = (1 << TWINT) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
//Warten auf Abschluss der Aktion:
TWIStatus = i2c_status();
if ((TWIStatus == 0x28) || (TWIStatus == 0x30))
{
TWIStatus = 0; //kein Fehler
}
}
}
//Senden der Stoppbedingung:
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return(TWIStatus);
}
uint8_t i2c_status()
{
//Warten, bis das Interrupt-Bit gesetzt und so das erfolgreiche Ende einer Busaktion angekündigt wurde
while(!(TWCR & (1 << TWINT)));
//Ausmaskieren der Prescaler-Bits und Rückgabe des Statuswertes
return(TWSR & 0xF8);
}
... und für den Slave:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/twi.h>
uint8_t i2c_getbyte(void);
void i2c_init(uint8_t Adress);
uint8_t i2c_status(void);
int main (void)
{
DDRD = 0xFF;
uint8_t buffer = 0;
i2c_init(26);
buffer = i2c_getbyte(); //Empfangen des Bytes
PORTD = buffer; //Ausgabe zur Kontrolle
while(1);
return(0);
}
void i2c_init(uint8_t Adress)
{
TWSR = 0;
TWAR = (Adress << 1);
TWCR = (1 << TWEA) | (1 << TWEN);
TWDR = 0xFF;
}
uint8_t i2c_getbyte(void)
{
uint8_t Status = 0;
uint8_t Byte = 0;
//Warten, bis der Slave angesprochen wurde
Status = i2c_status();
Byte = Status;
TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN); //TWINT-Bit zurücksetzen, um nächste Aktion auszulösen
return(Byte);
}
uint8_t i2c_status()
{
//Warten, bis das Interrupt-Bit gesetzt und so das erfolgreiche Ende einer Busaktion angekündigt wurde
while(!(TWCR & (1 << TWINT)));
//Ausmaskieren der Prescaler-Bits und Rückgabe des Statuswertes
return(TWSR & 0xF8);
}
Herzlichen Dank fürs Lesen; vielleicht hat ja einer eine Idee.
Schönes Wochenende,
ikarus_177