Forum: Compiler & IDEs Hilfe bei I2C (Peter Fleury)


von Dominik G. (moondryl)


Lesenswert?

Hallo,
ich wollte gerade die I2C-Library von Peter Fleury zum Laufen bekommen 
aber irgendwie hängt sich das Programm sofort auf.
Ich nutze einen Atmega8A-PU mit einem 16MHz Quarz.
Anfangen wollte ich, indem ich bei einer DS1307 das Register 0x00 einmal 
beschreibe (damit sie anfängt zu zählen) und danach auslese.
Der AVR schaltet die LED noch an und dabei bleibt es (sie bleibt an und 
nichts passiert mehr). Ich habe auch mal alles auskommentiert und nur 
den I2C-Bus gestartet und wieder gestoppt (ohne etwas zu schreiben oder 
zu lesen); mit dem selben Ergebnis.
Habe ich etwas übersehen? Gehe ich da zu naiv ran?
Das ganze sieht dann so aus:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <uart.h>
5
#include <avr/interrupt.h>
6
#include <i2cmaster.h>
7
8
#define UART_BAUD_RATE 9600
9
10
#define DS1307  0xD0
11
char buffer;
12
13
int main(void)
14
{
15
  sei();
16
  DDRB = (1 << PB0);
17
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
18
  i2c_init();
19
  
20
    while(1)
21
    {
22
        PORTB ^= ( 1 << PB0 );  // Toggle
23
    
24
        i2c_start(DS1307+I2C_WRITE);
25
        i2c_write(0x00);                        
26
        i2c_write(0x75);
27
        i2c_stop();
28
        i2c_start_wait(DS1307+I2C_WRITE);
29
        i2c_write(0x00);
30
        i2c_rep_start(DS1307+I2C_READ);
31
        buffer = i2c_readNak();
32
        i2c_stop();
33
    
34
        uart_puts(buffer);
35
        _delay_ms(1000); 
36
    }
37
}

von Karl H. (kbuchegg)


Lesenswert?

Du willst hier

>        uart_puts(buffer);

ganz sicher nicht die Funktion uart_puts benutzen.
Das 's' in puts steht für String. Du hast aber keinen String. Du hast 
ein einzelnes Byte.

Du könntest zb

  char str[10];
  sprintf( "0x%02x ", (int)buffer );
  uart_puts( str );

machen. Und ich wette mal, du wirst dann eine Hexzahl auf deiner Ausgabe 
sehen, die keine sichtbare ASCII Repräsentierung hat.


Natürlich nur, wenn deine UART funktioniert und das hier
> Ich nutze einen Atmega8A-PU mit einem 16MHz Quarz.
und das hier auch insofern der Realität entspricht, dass der Quarz auch 
benutzt wird.

D.h. ich würde, nur um sicher zu gehen, am Anfang einfach mal einen 
konstanten Text ausgeben.
1
int main(void)
2
{
3
  sei();
4
  DDRB = (1 << PB0);
5
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
6
  i2c_init();
7
8
  uart_puts( "Testing I2C\n" );
9
10
  ...

nur um sicher zu gehen, dass die UART auch wirklich funktioniert.

von Dominik G. (moondryl)


Lesenswert?

Autsch ok, da hast du Recht. Die Ausgabe kann so nicht funktionieren.
Das ändert aber nichts am verhalten. Werde mich nachdem I2C vernünftig 
funktioniert darum kümmern.
Kommentiere ich alles aus bis auf
1
 
2
i2c_start(DS1307+I2C_WRITE);
3
i2c_stop();
bleibt er immernoch hängen (LED bleibt an).

Edit: Hatte gerade gesehen, dass du noch mehr geschrieben hattest.
Ich programmiere den Atmega mit AVR Studio 4. Dort sind die Fuses auf 
externen Quarz gesetzt. Wenn ich nur die LED blinken lasse, blinkt sie 
auch im Sekundentakt; würde 16MHz nicht stimmen, wäre das doch nicht so 
oder?

Der UART funktioniert. Habe ihn vorher getestet mit einem konstanten 
String:
1
 uart_puts( "Hello World!\n" );
Über ein Terminal kam auch im Sekundentakt Hello World! an.

Also ich hatte einzeln zuerst das Blinken getestet (hat funktioniert), 
dann einzeln den UART und nun wollte ich I2C integrieren.


Grüße

Dominik

von Karl H. (kbuchegg)


Lesenswert?

Das
1
/*************************************************************************  
2
  Issues a start condition and sends address and transfer direction.
3
  return 0 = device accessible, 1= failed to access device
4
*************************************************************************/
5
unsigned char i2c_start(unsigned char address)
6
{
7
    uint8_t   twst;
8
9
  // send START condition
10
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
11
12
  // wait until transmission completed
13
  while(!(TWCR & (1<<TWINT)));
14
15
  // check value of TWI Status Register. Mask prescaler bits.
16
  twst = TW_STATUS & 0xF8;
17
  if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
18
19
  // send device address
20
  TWDR = address;
21
  TWCR = (1<<TWINT) | (1<<TWEN);
22
23
  // wail until transmission completed and ACK/NACK has been received
24
  while(!(TWCR & (1<<TWINT)));
25
26
  // check value of TWI Status Register. Mask prescaler bits.
27
  twst = TW_STATUS & 0xF8;
28
  if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
29
30
  return 0;
31
32
}/* i2c_start */
33
34
/*************************************************************************
35
 Terminates the data transfer and releases the I2C bus
36
*************************************************************************/
37
void i2c_stop(void)
38
{
39
    /* send stop condition */
40
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
41
  
42
  // wait until stop condition is executed and bus released
43
  while(TWCR & (1<<TWSTO));
44
45
}/* i2c_stop */

sind die Fleury I2C start und stop Routinen. Die einzige Stelle an der 
der Mega hängen kann, besteht in den

  // wait until transmission completed
  while(!(TWCR & (1<<TWINT)));

bzw.

  // wait until stop condition is executed and bus released
  while(TWCR & (1<<TWSTO));

Schleifen. Das sich aber der Mega hier selbst die Freigabe gibt, nachdem 
er alles rausgetaktet hat, kann da normalerweise nichts hängen.

-> Mal ein paar UART Ausgaben da dazwischen reinfummeln um zu sehen, wo 
es ins Stocken kommt. Deine UART funktioniert ja :-)


Der Watchdog ist ausgeschaltet?

von Dominik G. (moondryl)


Lesenswert?

Also, ich habe mal das ganze mal mit Ausgaben versehen:
1
unsigned char i2c_start(unsigned char address)
2
{
3
  uint8_t   twst;
4
  
5
  uart_puts("Start\n");
6
7
  // send START condition
8
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
9
  
10
  uart_puts("Send Start condition\n");
11
12
  // wait until transmission completed
13
  while(!(TWCR & (1<<TWINT)));
14
  
15
  uart_puts("while1\n");
Er kommt dabei bis "Send Start condition". Danach bricht er ab und das 
war es auch. Led leuchtet und keine weitere Ausgabe.

Der Watchdog sollte aus sein. Zumindest ist in AVR Studio bei "WTDON" 
kein Haken gesetzt.

Grüße

Dominik

EDIT: Halbes Kommando zurück! Manchmal schafft er es wohl auch noch in 
die erste While-Schleife und in die erste if-Abfrage. Spätestens dann 
ist aber schluss. Und meißtens schafft er es auch wie gesagt nur bis 
"Send Start condition".

EDIT2: Mal eine Frage ob ich die Library überhaupt richtig verwende. Ich 
muss doch die i2cmaster.h mit #include einfügen und die twimaster.c per 
"add existing file" meinem Projekt hinzufügen; oder habe ich die Doku 
falsch verstanden?

von Joachim .. (joachim_01)


Lesenswert?

EDIT2: Mal eine Frage ob ich die Library überhaupt richtig verwende. Ich
muss doch die i2cmaster.h mit #include einfügen und die twimaster.c per
"add existing file" meinem Projekt hinzufügen; oder habe ich die Doku
falsch verstanden?
>EDIT2: ... oder habe ich die Doku falsch verstanden?
Nee, ist richtig so. Ausserdem: Würde die xxx.c fehlen, so würde der 
Compiler abbrechen weil er den Code nicht findet.

Stimmt denn auch die Taktgeschwindigkeit?

Biste sicher daß deine Hardware richtig geht? Bei mir war da mal nen 
Problem. Du brauchst auf jeder Leitung nen Pull-up von ca 3.3k. Die 
eingebauten Pull-ups im ATMega gehen aber auch.

Haste nen Oszi? So was hilft hier immer ungemein. Selbst ein altes 
analoges, extern mit nen Portbit getriggert + Code in Wiederholschleife 
ist fast so gut wie ein Speicher-Oszi.

von pepone (Gast)


Lesenswert?

Das Problem hatte ich auch. Im Buch "Powerprojekte mit Arduino und C" 
3645651314 habe ich die Loesung gefunden. Es sind nur ein paar 
zusaetzliche Nop einzufuegen, dass das Timing bei 16 Mhz klappt.
( Denke es war die *.s  -Datei)

von Dominik G. (moondryl)


Lesenswert?

Ahhhh, ich könnte meinen Kopf gegen die Wand schlagen.:)
Es funktioniert mittlerweile. Hatte mich heute nochmal in Ruhe 
hingesetzt und ich bin wirklich dämlich. Hatte mir ein zweites 
Breadboard gekauft. Dort sind die Vcc und GND Linien außen in der Mitte 
getrennt; wohl ganz nützlich, wenn man zwei Spannungen an einem Board 
haben möchte. Da es das gleiche Board wie mein altes ist, hatte ich 
darauf gar nicht geachtet. Ich hatte noch gemessen, ob 5V denn bei der 
DS1307 ankommen und dem war so, da Vcc und GND noch vor der Trennung in 
der Mitte angeschlossen waren; die 4,7k-Pullups aber dahinter; an die 
hatte ich ja auch gedacht.

Also nochmal: mein Fehler, peinlich, Asche auf mein Haupt. Aber es geht 
jetzt alles. :)

Danke für eure tatkräftige Hilfe!

Viele Grüße

Dominik

von Joachim .. (joachim_01)


Lesenswert?

>Biste sicher daß deine Hardware richtig geht?
Mein Tip für die Zukunft:

1. Visuelle Inspektion.

2. ALLE Leitungen der Versorgungsspannung richtig messen.

3. Signale richtig messen/simulieren.

4. Software prüfen.

5. Problem hier posten.

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.