Forum: Mikrocontroller und Digitale Elektronik Interrupt bei I2C - Startkondition wird nicht ausgelöst


von Tobias J. (tobiasjohn) Benutzerseite


Lesenswert?

Hallo zusammen,
mein Problem:
ich nutze das MSSP-Modul eines 16f874 um ein EEPROM zu lesen.
Nun habe ich einige I2C-Routinen ausprobiert und musste leider 
feststellen, dass schon das senden der Start-Condition Probleme 
bereitet.
1
void i2c_start() {
2
  SSPIF = 0;
3
  SEN=1; //Bus-Übernahme anweisen
4
  while(SSPIF==0); // while(SEN) <== Alternativ
5
}
Wenn ich while(SSPIF==0) benutze bleibt der PIC an der stelle hängen.
Wenn ich while(SEN) verwende, dann geht es weiter, aber es gibt keine 
Start-Bedingung.

In einer Init-Methode stelle ich die Interrupts ein
1
GIE = 1; // enable interrupts
2
PEIE = 1; // enable peripheral interrupts => braucht man wohl nicht, aber habe ich mal mit reingenommen
3
SSPIE = 1; // enable interrupt for SSPmodule
4
SSPIF = 0; // CLR SSP-Interrupt-Flag
Die I2C-init-Methode sieht so aus
1
void i2c_init() {
2
  TRISC3=1;           // set SCL and SDA pins as inputs
3
  TRISC4=1;
4
5
  SSPADD = 40;//SSPADD_VAL; // Siehe header-datei 100 KHz
6
7
  // SSPCON1 - egisters
8
  SSPCON = 0x28; // Enables Serial Port Mode / I2C Master Mode
9
10
  // SSPCON2 - Registers
11
  SSPCON2 = 0x00;
12
13
  // SSPSTAT REGISTERS
14
  SSPSTAT = 0x80; //   SlewRate Control disabled
15
16
  SSPIF = 0; // CLR SSP-Interrupt-Flag
17
}

und folgendes sende ich in der Main-Methode
1
i2c_start();
2
i2c_write( 0xa0 );
3
i2c_stop();

das ist ja erstmal nicht viel. Ich wollte auch nur testen ob das EEPROM 
ein ACK sendet. Leider tuts das nicht. Es gibt nur ein NACK - Ich denke 
weil die Start-Bedingung fehlt.
Warum sendet der PIC die Start-Bedingung nicht. Bzw. warum wird das 
SSPIF - Flag nicht gesetzt?

Hier mal ein Bild von der Datenübertragung. 
http://img128.imageshack.us/my.php?image=i2cnostartnoackok9.png
(oder siehe Anhang)

Danke schonmal, Tobias

von Tobias J. (tobiasjohn) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ähm, Anhang hier :D Sorry

von Tobias J. (tobiasjohn) Benutzerseite


Lesenswert?

Hi,
ich habe festgestellt, dass wenn ich statt dem Start (SEN = 1) einen 
Restart (RSEN = 1) mache, dann wird die start-bedingung ausgegeben und 
das EEPROM sendet auch ein ACK.
D.h. anscheinend kann der PIC die Pegel (SDA und SCL) nicht richtig 
auswerten. Die Start-Bedingung wird ja nur gesendet wenn SDA und SCL 
high sind. Die Überprüfung fällt bei ReStart weg. Deshalb klappt das mit 
RSEN = 1.

Leider konnte ich trotzdem noch keine Daten empfangen und die Sache mit 
den Interrupts geht immer noch nicht.

Vielleicht kann mir da ja noch jemand helfen.

Gruß,
Tobias

von Tobias J. (tobiasjohn) Benutzerseite


Lesenswert?

Hallo,

ich habe herausgefunden, dass der PIC die Start-Bedingung deshalb nicht 
sendet, weil das MSSP-Modul ein Problem mit der Erkennung der Pegel an 
SDA und SCL hat.
Ein schreiben auf dem EEPROM ist interessanter weise möglich. Nur das 
Lesen vom EEprom geht nicht.

Ich habe jetzt eine Software-Variante geschrieben. Mit der geht es.

Vielleicht hat ja jemand noch DEN entscheidenden Tipp für die 
Hardware-Variante.

Danke und Gruß,
 Tobias

von Jens O. (pitcho)


Lesenswert?

Servus,
habe gerade das selbe Problem. Der setzt das SSPIF Bit nicht. Der Code 
ist eigentlich der gleich wie der von Tobias:

void  IIC(void)
{
  //Bus übernehmen
  SSPIF = 0;
                SEN = 1;  //Busübernahme anweisen
  while(SSPIF == 0);   //Testen ob Bus übernommen
  SSPIF = 0; //Ja, der Bus ist mein. SSPIF zurücksetzen!

  //Adresse senden
  SSPBUF = 0xA0;  //Adresse Slave
         while(SSPIF == 0);   //Warten bis 9.SCL-Takt
  SSPIF = 0;  //SSPIF zurücksetzen!

  //Datenbyte 1 senden
  SSPBUF = 0x04;              while(SSPIF == 0);   //Warten bis 
9.SCL-Takt
  SSPIF = 0;  //SSPIF zurücksetzen!

  //Datenbyte 2 senden
  SSPBUF = 0x03;              while(SSPIF == 0);  //Warten bis 
9.SCL-Takt
  SSPIF = 0;        //SSPIF zurücksetzen!

  //Bus wieder freigeben
  PEN = 1;                while(SSPIF == 0);  //Warten bis 9.SCL-Takt
  SSPIF = 0;  //SSPIF zurücksetzen!
}


void  INIT_IIC(void)
{
  //Einstellung der IO-Ports
  TRISC = 0b00011000; //1=Eingang, 0=Ausgang
        delay_ms(5);  //5ms Paus

  //Aktivieren des I2C-Interface
  SSPADD = 0x09;  //Busgeschwindigkeit: 0x09 => Fosc = 16 MHz  SSPSTAT = 
0x80;  //Status Register zurücksetzen
  SSPCON1 = 0b00001000; //Bit3-0: 1000 = IIC Master mode
  SSPCON2 = 0b00001000;
         SSPEN = 1;  //I2C-Mode enable
         GIE = 1;            //global interrupt enable
  PEIE = 1; //Peripheral Interrupt Enable bit
  SSPIE = 1;//Master Synchronous Serial Port Interrupt Enable bit


  SSPIF = 0;
}

von Jens O. (pitcho)


Lesenswert?

OK, Fehler gefunden. Lag an den Interrupts.

von Pic16f (Gast)


Lesenswert?

Hallo, ich weiß die Diskussion ist schon sehr alt, aber was war die 
genaue Lösung für das Problem?

Danke

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.