mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C Startcondition und dann nix mehr


Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich bin bald am verzweifeln.
Ich versuche einen I2C BUs zum laufen zu bringen, aber das einzige was 
funktionniert ist, dass die Startcondition gesendet wird.
Ich verwende den LPC2148 auf dem MBC2140 EvaluatuonBorad von Keil und 
debugge das Ganze mit Hitop5.

Pull-Ups habe ich bereits zwischen 1k und 10k variert.
Hier mein Source Code:
#include "LPC214x.h"                        /* LPC21xx definitions */
#include "type.h"
#include "I2C.h"
#include "irq.h"

char buf[]={'A','B','C','D','E'};
int count = 5, i = 0;

int temp = 0;
void i2c_init(void)
{
  PINSEL0 = 0;
  PINSEL1 = 0;
  PCONP |= (1 << I2C_POWER);

  PINSEL0 |=(1 << SCL0_PINSEL) | (1 << SDA0_PINSEL); //SDA und SCL Pins auf I2C-MOdus

  I20CONCLR |= (1 << STO) | (1 << AA) | (1 << STA) | (1 << SI);
  temp =   I20CONCLR;

  I20CONSET |= (1 << I2EN) ;//| (1 << STA);  //enable the I2C function.
  //temp = I20CONSET;

  I20SCLH = 100;
  temp = I20SCLH;
  I20SCLL = 50;
  temp = I20SCLL;

  VICIntSelect = 0;
  temp = VICIntSelect;
        //VICIntEnable = (1 << IE_I2C);
  temp = VICIntEnable;
  
  VICVectCntl0 = (DWORD)(IRQ_SLOT_EN | IE_I2C);
  temp = VICVectCntl0;
  VICVectAddr0 = (DWORD) I2C_ISR;
  temp = VICVectAddr0;  

  IOSET0 = 0x00000000;                // clear the ZEROs output
    IODIR0 = 0x00000000;               // set the output bit direction
}

int i2c_write()
{
  while (count--)
  {
    I20DAT = buf[i++];            //  load data into I2DAT-Register
    wait_for_SI();
    if (I20STAT != 0x28) return 0;    //  no acknowledge
  }
  return 1;
}

void warte(unsigned int dauer)
{
  while(dauer--);
}


void i2c_start(int addr)
{    
  VICIntEnable = (1 << IE_I2C);  
  I20CONSET |= (1 << STA) ;      //  set STA  
}


void wait_for_SI(void)
{
  long timeout = 400000;
            //  clear SI starts action
  while (timeout-- && !(I20CONSET & SI));    //  check SI with timeout
}


void i2c_stop(void)
{
  I20CONSET |= (1 << STO);    //  set STO
  I20CONCLR |=(1 << SI);      //  clear SI
}

void CCLK_set(void)
{ 
  PLLCFG |= (4 << MSEL); 
  PLLCFG |= (1 << PSEL);  //Fosc*5 =CCLK
  PLLFEED = 0xAA;
  PLLFEED = 0x55;

  PLLCON |= (1 << PLLE) | (1 << PLLC); //PLL Enable.//PLL Connect.
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  

  VPBDIV = 0;//00 VPB bus clock is one fourth of the processor clock.  
}

void I2C_ISR(void) //__irq
{  int temp1 = 0;
  temp1 = I20STAT;

  switch(temp1)
  {
    case 0x08:
    {  
      //I20DAT = 0x90; //addr
      temp1 = I20DAT;
      I20CONCLR |= (1 << SIC) | (1 << STA);
      break;
    }
    case 0x10:
    {
      I20DAT = 0x90;
      I20CONCLR |= (1 << SIC);
      break;
    }
    case 0x18:
    {
      if(count==0)
        i2c_stop();
      else
        count--;
      I20DAT = *(buf);
      I20CONCLR |= (1 << SIC);
      break;
    }
    case 0x20:
    {
      i2c_stop();
      I20CONCLR |= (1 << SIC);
      break;  
    }
    case 0x28:
    {
      if(count==0)
        i2c_stop();
      else
        count--;
      I20DAT = *buf;
      I20CONCLR |= (1 << SIC);
      break;
    }
    case 0x30:
    {
      i2c_stop();  
      I20CONCLR |= (1 << SIC);
      break;  
    }
  }

  VICVectAddr = 0;
    
}

Wie gesagt, Startcondition wird gesendet( erst SDA auf LOW gezogen und 
dann SCL), im I2CStatusregister ist der Wert 0x08, dann bleibt beides 
auf LOW, bis in der ISR das SI-Flag gelöscht wird.

Was komisch ist, ich hatte einmal den Jumper7(für die, die des 
MCB2140Schematics zufällig vor sich haben) noch an, als ich den I2C1 
verwendete, und dann bekamm ich ein CLocksignal auf SCL, das nicht mehr 
aufhörte, aber das SI-Flag wurde nicht merh gesetzt. Über den Jumper 7 
wird SDA über einen Kondensator mit 100nF auf Ground gezogen und über 
einen 22k Wiederstand auf HIGH. Als ich den Jumper entfernte war es 
genauso, wie als ich den I2c0 verwendet habe.

Wie bekomme ich es jetzt hin, dass nicht nur die Startcondition sondern 
auch die Slaveaddresse gesendet wird? Und dann vielleicht auch mal Daten 
gesendet werden können?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind die obligatorischen Pullups dran?

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pull-Ups habe ich bereits zwischen 1k und 10k variert.
Da aber 3mA fließen müssen,  werde ich eher die kleineren Widerstände 
verweden, wenn die Pullups nicht dran wären, könnte der IC ja nichts auf 
LOW ziehen.
Ich hatte schon den Verdacht dass ich vielleicht Bus-Arbitration 
verliere, aber gegen wen?
Ich hatte berits einen IC(den DS1624) angeschlossen ,habe jetzt aber, um 
Fehler beim DS1624 aus zu schließen, nur SDA und SCL über einen Pullup 
an High(3,3V) abgeschlossen.
Das komische ist ja, dass er die Startconidition macht und in der ISR 
die Slaveaddresse in I2DAT lädt, aber dann nichts passiert, nicht mal 
ein Clock genertiert wird. Ich schau das ganz natürlich mit dem Oszi an.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Unabhängig vom I2C Code kommt mir die Initialisierung vom Takt etwas 
seltsam vor. Du schaltest dich beispielsweise auf den PLL-Takt bevor die 
PLL sich überhaupt stabilisert hat (locked), wenn ich mal meinen Code 
für LPC2106 und LPC2129 als Massstab nehme.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In deinem Code fehlt das Hautprogramm. Aufruf von i2c_init, usw.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kennst du die NXP Application Notes AN10331 (PLL) und AN10369 (u.A.I2C)?

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ja ich habe den Teil mit der Main-Schleife in einer anderen Datei 
gehabt.
Ja die Application Notes kenne ich, habe mich so weit auch daran 
gehalten.
A.K. könnsest du deinen Code vom 2106 und 2129 eventuell mal hier rein 
stellen, würde mich mal interessieren.
Danke schon mal. Gruß Markus
int main (void)
{

  i2c_init();
  i2c_start(0x90);
  
  while(1)
  {
    i2c_write();    
  }
  return 0;

}

Autor: A. K. (prx)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Viel Vergnügen ;-).

Fehlt natürlich ein bischen was drum herum und ist für anderen Compiler, 
als nix für "einfach übersetzen und läuft".

Ich weiss nicht mehr wieviel ich davon getestet hatte. Ist nicht 
produktiv im Einsatz. Einfachen Basistest gab es aber.

Autor: A. K. (prx)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Für die PLL. Dieser Code ist produktiv im Einsatz.

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, Vielen Dank für den Code. Mir ist aber aufgefallen, dass ich den PLL 
garnicht verwende, da ich CCLK_set() garnicht aufrufe. Dann sollte der 
PLL ja defaultmäßig abgschaltet sein und CCLK = Fosc.
Habe jetzt I20SCLH auf 20 und I20SCLL auf 10 gesetzt, dann sollte mit 
einer Quarzfrequenz von 12MHZ die Bitrate 100kB betragen.
Was mir noch auffällt. Wenn ich an SCL messe erhalte ich 800ns bevor 
dieser abfällt einen kleinen Spannungseinbruch von 650mV. Könnte dass 
der Zeitpunkt sein, an dem SDA auf LOW geht?

Leider ändert sich bisher nichts daran, dass SDA und SCL auf LOW gehen 
und dann nichts mehr passiert, bis ich das SI Flag in der ISR lösche und 
dann beide wieder auf HIGH gehen.

Wäre für jeden Rat dankbar.
Gruß Markus

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe jetzt mal alle für diese Problem irrelavnten Codeteile raus 
gestrichen.

Die Slaveaddresse ist erstmal irrelavant, da ich keinen Slave angehängt 
habe, sindern SDA und SCl über Pullups auf HIGH gezogen habe.

Ich hoffe jemand kann mit diesem Problem was Anfangen.
Gruß Markus
#include "LPC214x.h"                        /* LPC21xx definitions */
#include "type.h"
#include "I2C.h"

int main (void)
{
  i2c_init();
  i2c_start(0x90);
      
  return 0;

}

void i2c_init(void)
{
  PINSEL0 = 0;
  PINSEL1 = 0;
  PCONP |= (1 << I2C_POWER);

  PINSEL0 |=(1 << SCL0_PINSEL) | (1 << SDA0_PINSEL); //SDA und SCL Pins auf I2C-MOdus

  I20CONCLR |= (1 << STO) | (1 << AA) | (1 << STA) | (1 << SI);
  I20CONSET |= (1 << I2EN) ;//| (1 << STA);  //enable the I2C function.

  I20SCLH = 100;
  I20SCLL = 50;

  VICIntSelect = 0;
  //VICIntEnable = (1 << IE_I2C);
   
  VICVectCntl0 = (DWORD)(IRQ_SLOT_EN | IE_I2C);
  VICVectAddr0 = (DWORD) I2C_ISR;
 
}

void i2c_start(int addr)
{    
  VICIntEnable = (1 << IE_I2C);  
  I20CONSET |= (1 << STA) ;      //  set STA  
}

void I2C_ISR(void) 
{  int temp1 = 0;
  temp1 = I20STAT;

  switch(temp1)
  {
    case 0x08:
    {  
      I20DAT = 0x90; //addr
      I20CONCLR |= (1 << SIC) | (1 << STA);
      break;
    }
  }

  VICVectAddr = 0;
    
}

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In
  I20CONSET |= (1 << STA);
  I20CONCLR |= (1 << SIC) | (1 << STA);
ergibt |= keinen Sinn, ganz besonders nicht bei ICONCLR.

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum macht |= keinen Sinn?

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verhaspelt sich der LPC vielleicht irgendwo beim Interrupt? Wird die ISR 
angesprungen (evtl. zum Test  dort LED setzen)? Vielleicht ist es für 
den Anfang besser, erst einmal ohne Interrupt, nur mit Polling zu 
arbeiten.

Gruss
Mike

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus D. schrieb:

> Warum macht |= keinen Sinn?

Erstens weil CONCLR als WO definiert ist. Als nicht lesbar.

Zweitens weil der tiefere Sinn dieser beiden Sichtweisen auf das gleiche 
Register genau darin besteht, den Lesevorgang der |= Operation 
überflüssig zu machen.

Lies nochmal nach wie die funktionieren.

Autor: A. C. (michael1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar, des |= war es.
Das hatte ich nciht gewusst.
Naja wieder wa gelernt.
Vielen dank für die Hilfe!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.