Forum: Mikrocontroller und Digitale Elektronik AVR I2C Anfängerprobleme


von Peter (Gast)


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
}

von Hubert G. (hubertg)


Lesenswert?

Bitrate etwas zu hoch?
PullUp vorhanden?

von Falk B. (falk)


Lesenswert?

@ Peter (Gast)

>ich versuche von Arduino wegzukommen und von Grund aus die Programme
>selber zu programmieren.

Warum? Ist es dir zu langweilig? Willst du das Rad immer wieder neu 
erfinden?

von Peter (Gast)


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!

von Frickelfritze (Gast)


Lesenswert?

Erfinde nicht neu sondern verwende eine existierene Sammlung
von Funktionen.

http://homepage.hispeed.ch/peterfleury/avr-software.html

von Peter (Gast)


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.

von Doppelkeks (Gast)


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 :)

von Peter (Gast)


Lesenswert?

TWInt wird dich gesetzt und gewartet wird auch der Fehler kommt ja beim 
prüfen vom Status nach dem Start!

von Felix A. (madifaxle)


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
}

von Doppelkeks (Gast)


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.

von Felix A. (madifaxle)


Lesenswert?

Ich sehe gerade, dass du TWIE auf 0 setzt und deine I2C-Hardware damit 
deaktivierst bzw. den INT abschaltest.

Ah, du nutzt den Int ja nicht, vergiss das dann.

von Felix A. (madifaxle)


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

von Dieter F. (Gast)


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.

von R. R. (elec-lisper)


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.

von Peter (Gast)


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 :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.