AVR I2C Anfängerprobleme

Gast #4346922
Lesenswert?
• ▲
▼
Hallo,
ich versuche von Arduino wegzukommen und von Grund aus die Programme 
selber zu programmieren. Jetzt möchte ich gerne zwischen zwei ATmega via 
I2C kommunizieren. Auf dem Slave läuft dazu noch das Arduino Programm 
welches via I2C empfangene Daten auf dem Serialport ausgibt. Auf dem 
Master habe ich das Programm laufen welches ich aus dem Datenblatt vom 
Atmega erlesen habe. Nur leider gibt das Programm sofort beim ersten 
Statuscheck eine Fehlerroutine aus (blinkende LED). könntet ihr bitte 
das Programm prüfen und mir sagen wo der Fehler liegt? Danke!
1
#define START 0x08
2
#define Slave 1
3
#define MT_SLA_ACK 0x18
4
#define MT_DATA_ACK 0x28
5
#define F_CPU 16000000
6

7
#include <avr/io.h>
8
#include <util/delay.h>
9

10
uint8_t Zahl = 0;
11

12
void Error(void)
13
{
14
  while (1)
15
  {
16
PORTB &= ~(1<<PB5);
17
_delay_ms(100);
18
PORTB |= (1<<PB5);
19
_delay_ms(100);  
20
  }
21
}
22

23
void TWIStart(void)
24
{
25
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
26
  while (!(TWCR & (1<<TWINT)));
27
}
28

29
void TWIStop(void)
30
{
31
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
32
}
33

34
int main(void)
35
{
36
  DDRB |= (1<<DDB5);
37
  PORTB &= ~(1<<PB5);
38
  _delay_ms(1000);
39
  
40
    while(1)
41
  {
42
    PORTB |= (1<<PB5);
43
    TWIStart();
44
    if ((TWSR & 0xF8) != START) Error();
45
    TWDR = (Slave<<1);
46
    TWCR = (1<<TWINT) | (1<<TWEN);
47
    while (!(TWCR & (1<<TWINT)));
48
    if ((TWSR & 0xF8) != MT_SLA_ACK) Error();
49
    TWDR = Zahl;
50
    TWCR = (1<<TWINT) | (1<<TWEN);
51
    while (!(TWCR & (1<<TWINT)));
52
    if ((TWSR & 0xF8) != MT_DATA_ACK) Error();
53
    TWIStop();
54
        Zahl++;
55
    _delay_ms(1000);
56
    PORTB &= ~(1<<PB5);
57
    _delay_ms(1000);
58
    }
59
}
Gast #4347080
Lesenswert?
• ▲
▼
Hallo,

Pullups sind vorhanden! Habe keinen Vorteiler bestimmt. Vielleicht liegt 
da der Fehler? Takt ist 16 MHz. Nur da der Error schon beim ersten 
Prüfen passiert müsste ja das schon Schuld daran sein, dass nicht einmal 
ein Startbefehl funktioniert?

Warum weg von Arduino? Arduino ist perfekt zum schnellen probieren aber 
leider gibt es in den fertigen Codes viele Schleifen die einen 
Ausbremsen. Vielleicht nicht gerade beim I2C aber z.b. beim Ansteuern 
eines Displays habe ich bemerkt, dass ich mit meinem eigenen Code viel 
schneller Darstellungen habe als über die vorgegeben Codes. Darum möchte 
ich gerne meinen Code selber schreiben und wissen wenn etwas nicht geht 
warum und genau so wenn etwas geht warum!
Gast #4347214
Lesenswert?
• ▲
▼
Danke für die Sammlung. Werde ich morgen studieren! Aber trotzdem muss 
doch in meinem Versuch ein Fehler sein. Ich habe es Schritt für Schritt 
aus dem Datenblatt übernommen. Dann muss es doch auch gehen. Ich möchte 
es gerne nach dem Datenblatt machen, da es so viele MCU's gibt für die 
es leider keiner Vorgefertigten Codes gibt und die man nur an Hand vom 
Datenblatt programmieren kann. Daher jetzt mit einer MCU bei der es 
viele Lösungen gibt, da man sich das besser kontrollieren kann.
Gast #4347416
Lesenswert?
• ▲
▼
Hi,

aus dem TWI tutorial:

"Zuerst muss vom Master ein START-Signal auf den Bus gegeben werden. 
Dies erfolgt durch Schreiben eines speziellen Wertes in TWCR. Nach 
Abschluss der Operation wird TWINT gesetzt. Die Logik wartet nun so 
lange, bis durch den Anwender das Flag wieder gelöscht wurde (durch 
Schreiben einer '1'). Unmittelbar nach dem Löschen von TWINT beginnt die 
Logik damit das START-Signal zu senden. "

Wenn ich das richtig verstehe musst du nach deinem TWI_Start erst das 
TWINT bit schreiben (zurücksetzen).

Denk auch dran die richtige Adresse vom Slave zu nutzen, sonst gibts 
kein ACK :)
#4347457
Lesenswert?
• ▲
▼
Meine Initroutine sieht so aus:
1
// --- HW initialisieren ---
2
  // Festlegung der BAUD-Rate
3
  // SCL-Frequenz = Prozessortakt / (16 + 2 * TWBR * Prescaler)
4
  // Bei ~100kBaud kHz und Prozessortakt 3,6864 MHz: 
5
  // 16+2*TWBR*TWPS ~= 38 -> TWBR = 11 bei TWPS = 0 (CK/1)
6
  TWBR = bd;      // Baudrate
7
  TWSR = presc;   // Prescaler
8
  TWDR = 0xFF;    // default content, bus released
9
    // TWI initialisieren
10
  TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);

Meine Funktion zum Starten sieht so aus (vorletzte Zeile):
1
void I2MGenerateStartCondition(uint8_t* daten, uint8_t anzahl)
2
{
3
  uint8_t i = 0;
4

5
    // Schnittstelle in Aktion
6
  i2cInUse = TRUE;
7

8
  for (i = 0; i < anzahl; i++)
9
  {
10
    i2Mtxbuffer[ i ] = daten[ i ];    // Daten in Puffer übertragen
11
  }
12

13
  txbufPtr = I2M_INITIAL_BUFPTR_STATE;// Beginn mit SLA an Stelle 2 (i2Mtxbuffer[1])
14
  rxbufPtr = 0;
15

16
    // Schnittstelle eine Startcondition generieren lassen
17
  TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
18
}
Gast #4347460
Lesenswert?
• ▲
▼
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
  while (!(TWCR & (1<<TWINT)));

Während du in der while-loop wartest wird das TWINT gesetzt. Laut 
Tutorial wartet die Logik nun so lange bis das flag gelöscht wird und 
beginnt dann damit das Start-Signal zu senden. Versuche also einfach mal 
nach der while-Schleife das TWINT nochmal zu setzen um es damit zu 
löschen.
#4347474
Lesenswert?
• ▲
▼
Also, nach nochmaligem gründlicherem Lesen eine Frage:
was tust du mit TWBR und TWSR? Schreibst du hier die passenden Werte 
rein, damit die Hardware überhaupt einen Takt bekommt?

Wähle mal TWBR = 50 und stelle den Prescaler auf 16. Dann sollte 
zumindest schonmal die Startcondition kommen
Gast #4347525
Lesenswert?
• ▲
▼
Ohne mir Deinen Code angeschaut zu haben:

Bei I2C / SPI & Co. bin ich ohne Logic-Analysator bzw. Bus Pirate nicht 
glücklich geworden. Wenn Du nicht siehst was passiert fällt eine 
Fehlersuche wirklich schwer.

Es mag Experten geben, die das alles aus der hohlen Hand schütteln - ich 
gehöre nicht dazu, aber seit ich die Aktionen am Bus verfolgen kann 
finde ich meine Fehler relativ schnell.
#4347568
Lesenswert?
• ▲
▼
Tolle Kommentare @Rad neuerfinden. Wie sonst soll man ein tieferes 
Verständnis von Protokollen bekommen? Die TWI vom AVR zu nutzen ist ein 
super Anfang mehr zu verstehen. Der nächste Schritt ist dann I2C 
komplett in SW zu machen. Dann kann man später beruhigt auf fertige 
Bibliotheken zurückgreifen und weiss besser bescheid wo es bei Problemen 
haken könnte.

Alleine vom Quellcode lesen lernt man wenig. Aus eigenen Fehlern lernt 
man (bzw manche) viel besser.

Als nächstes kommen Ratschläge wie gleich alles sein zu lassen, weil 
alles doch schon erfunden und verbessert ist. Soll man sich ein Tablett 
kaufen. Damit kann man dann nen ganzen Bildschirm blinken lassen und 
Pay-to-Win Spiele und P**nos gucken.
Gast #4348001
Lesenswert?
• ▲
▼
Hallo,
habe den Fehler gefunden. Ich habe den Takt nicht eingestellt und somit 
konnte es nicht funktionieren. Und siehe da auch mit dem Datenblatt kann 
man die Funktionen zum laufen bekommen nicht nur durch fertige Codes :)

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.