www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430F4794 und I2C EEPROM


Autor: RoyW (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ihr Profis ...

ich beschäftige mich nun ein paar Tage mit dem MSP430F4794 und einem I2C 
EEPROM (M24C32).

Ich glaube das schreiben (Byteweise) funktioniert.
Wenn ich aber die Bytes wieder lesen will, habe ich eine Verschiebung 
drin so...

Meine Frage ist eigentlich : hat schon jemand I2C Routinen für I2C 
EEproms die er mir schicken könnte ? oder Code Schnipsel o.ä.

hier sind mal meine Anfänge :

unsigned char EEPROM_ByteWrite(unsigned int address,unsigned char data)
{
  while (UCB0STAT&UCBBUSY);  // wait until I2C module has finished all 
operations

  I2CBuffer[0]  = ((unsigned char)*((unsigned char*)&address + 1)); 
// calculate high byte
  I2CBuffer[1]  = ((unsigned char)*((unsigned char*)&address + 0)); 
// calculate low byte
  I2CBuffer[2]  = data;
  I2C_WRITECNT  = 3;                   // set I2CBuffer Pointer

  IFG2 &= ~(UCB0TXIFG | UCB0RXIFG);   // clear Access ready interrupt 
flag
  IE2  &= ~ (UCB0RXIE | UCB0TXIE);     // RX / TX Interrupt sperren
  P3DIR |= BIT0;P3OUT&=~BIT0;
  UCB0CTL1 |= UCTR ;           // Repeated start condition generation + 
R/W
  UCB0CTL1 |= UCTXSTT;           // Repeated start condition generation 
+ R/W
  while (!(IFG2 & UCB0TXIFG));      // wait until I2C module has 
finished all operations
  IFG2 &= ~UCB0TXIFG;
  unsigned char i;
  for (i=0;i<I2C_WRITECNT;i++)
  {
     UCB0TXBUF = I2CBuffer[i];
     while (!(IFG2 & UCB0TXIFG));      // warten bis Byte gesendet wurde
     IFG2 &= ~UCB0TXIFG;
  }
  UCB0CTL1 |= UCTXSTP;           // Stop condition
  while (UCB0CTL1 & UCTXSTP);           // Loop until I2C STT is sent
  P3OUT |=BIT0;
  DelayMsI2C(12);             // (10ms warten laut Datenblatt !)
  return 1;
}


unsigned char EEPROM_RandomRead(unsigned int Address)
{
  unsigned char rec=0;
  while (UCB0STAT&UCBBUSY);  // wait until I2C module has finished all 
operations

  I2CBuffer[0]  = ((unsigned char)*((unsigned char*)&Address + 1)); 
// calculate high byte
  I2CBuffer[1]  = ((unsigned char)*((unsigned char*)&Address + 0)); 
// calculate low byte

  I2C_WRITECNT  = 2;                   // set I2CBuffer Pointer

  IFG2 &= ~(UCB0TXIFG | UCB0RXIFG);   // clear Access ready interrupt 
flag
  IE2  &= ~ (UCB0RXIE | UCB0TXIE);     // RX / TX Interrupt sperren
  UCB0CTL1 |= UCTR | UCTXSTT;       // Start
  while (!(IFG2 & UCB0TXIFG));      // warten bis Start Byte gesendet 
wurde

  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 1));
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0TXIFG;
  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 0));
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0TXIFG;

  rec = UCB0RXBUF;
  UCB0CTL1 &= ~UCTR;          // R/W löschen
  UCB0CTL1 |= UCTXSTT;           // start condition generation
  while (UCB0CTL1 & UCTXSTT);      // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0RXIFG;
  rec = UCB0RXBUF;
  UCB0CTL1 |= UCTXSTP;           // Stop condition
  while (UCB0CTL1 & UCTXSTP);           // Loop until I2C STT is sent
  DelayMsI2C(1);             // warten laut Datenblatt !!!
  return rec;
}


wenn ich zuerst 16 Bytes schreibe von 0 bis 15 und dort den Wert 0 bis 
15 rein schreibe bekomme ich dann beim lesen auf Addr 0 und 1 eine 0 und 
ab Addr2 dann 1..15 .

Ich hoffe ihr könnst verstehen was ich meine ...

Wäre super wenn jemand schon tiefer in diesem Tham drin wäre und helfen 
könnte.

Ich danke euch auf jedenfall schon mal im Voraus.

Gruß

Royw

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich steigt bei deinem Code jetzt nicht ganz durch, ich pack mal meinen 
Code rein. Der ist zwar auch noch nicht 100%ig fertig, funktioniert aber 
schon fehlerfrei (Mit FRAM).
Geschrieben für MSP430F2254.

//////////////////////////////////////////////////////////////////////////
unsigned char fram_write_byte (unsigned int addr, unsigned char data)
{
  unsigned char addr_h;
  unsigned char addr_l;

  addr_h = addr>>8;
  addr_l = addr;

//  UCB0STAT &=~UCNACKIFG;

  UCB0I2CSA = I2C_ADDR_FRAM;

  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
  UCB0TXBUF = addr_h;

  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet

  if (UCB0STAT & UCNACKIFG) return FALSE;

//  while (!(IFG2 & UCB0TXIFG));

  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_l;
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = data;
  while (!(IFG2 & UCB0TXIFG));

  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
  while(UCB0CTL1 & UCTXSTP);

  return TRUE;
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
unsigned char fram_write (unsigned int addr, unsigned char data_cnt, unsigned char *data)
{
  unsigned char addr_h;
  unsigned char addr_l;
  unsigned int  i;

  addr_h = addr>>8;
  addr_l = addr;


  UCB0I2CSA = I2C_ADDR_FRAM;

  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition

  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_h;
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_l;

  for(i = 0; i < data_cnt; i++)
  {
    while (!(IFG2 & UCB0TXIFG));
    UCB0TXBUF = data[i];
  }

  while (!(IFG2 & UCB0TXIFG));

  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
  while(UCB0CTL1 & UCTXSTP);

  return TRUE;
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
unsigned char fram_read_byte (unsigned int addr, unsigned char *data)
{
  unsigned char addr_h;
  unsigned char addr_l;

  addr_h = addr>>8;
  addr_l = addr;

//  UCB0STAT &=~UCNACKIFG;

  UCB0I2CSA = I2C_ADDR_FRAM;

  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition

//  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet
 /*
  if (UCB0STAT & UCNACKIFG)
  {
    UCB0CTL1 |= UCTXSTP;                // I2C stop condition
    UCB0STAT &=~UCNACKIFG;
    return FALSE;
  }
*/
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_h;
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_l;
  while (!(IFG2 & UCB0TXIFG));

  UCB0CTL1 &=~UCTR;         // I2C RX, start condition
  UCB0CTL1 |= UCTXSTT;         // I2C start condition

  while (!(IFG2 & UCB0RXIFG));
  *data = UCB0RXBUF;

  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
  while(UCB0CTL1 & UCTXSTP);

  return TRUE;
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
unsigned char fram_read (unsigned int addr, unsigned char data_cnt, unsigned char *data)
{
  unsigned char addr_h;
  unsigned char addr_l;
  unsigned int  i;

  addr_h = addr>>8;
  addr_l = addr;

//  UCB0STAT &=~UCNACKIFG;

  UCB0I2CSA = I2C_ADDR_FRAM;

  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition

//  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet
 /*
  if (UCB0STAT & UCNACKIFG)
  {
    UCB0CTL1 |= UCTXSTP;                // I2C stop condition
    UCB0STAT &=~UCNACKIFG;
    return FALSE;
  }
*/
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_h;
  while (!(IFG2 & UCB0TXIFG));
  UCB0TXBUF = addr_l;
  while (!(IFG2 & UCB0TXIFG));

  UCB0CTL1 &=~UCTR;         // I2C RX
  UCB0CTL1 |= UCTXSTT;         // I2C start condition

  for (i = 0; i < data_cnt; i++)
  {
    while (!(IFG2 & UCB0RXIFG));
    data[i] = UCB0RXBUF;
  }

  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
  while(UCB0CTL1 & UCTXSTP);

  return TRUE;
}
//////////////////////////////////////////////////////////////////////////

Autor: Roy ........ (royw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für deien Antwort.
Ich habe ma lunsere Routinen verglichen und habe festgestellt das sie 
eigentlich sehr ähnlich sind um nicht zusagen das gleiche tun sollten.
Was mir aber auffiel wenn man 2 mal nacheinander ein Frame_Read 
ausführt, sind die Daten des 2. Frame Read um eins verschoben.
Z.B. :

EEPROM Zelle 0 enthält 0 , Zelle 1 enthält 1 ... Zelle 15 enthält 15.

1. Frame_Read klappt noch super.

bei dem 2. Frame_Read steht dann in Addr0 ein zufallswert und in Zelle 1 
eine 0 in Zelle2 eine 1 ... Zelle 15 eine 14.

Jetzt habe ich herausgefunden das man hinter dem Stop senden einfach den 
UCB0RXBUF nochmal lesen sollte.Danach klappt das 2. Frame_Read auch !

(Vielleicht hilf dir das auch)

Vielen Dank für deine Hilfe.

Royw

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir sind doch 2 Sachen an deinem EEPROM_RandomRead Code aufgefallen 
(Siehe Kommentar im Code)
unsigned char EEPROM_RandomRead(unsigned int Address)
.....
  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 1));
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0TXIFG;
  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 0));
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0TXIFG;

// Wozu RX Buffer lesen?
  rec = UCB0RXBUF;
  UCB0CTL1 &= ~UCTR;          // R/W löschen
  UCB0CTL1 |= UCTXSTT;           // start condition generation
  while (UCB0CTL1 & UCTXSTT);      // warten bis Byte gesendet wurde
  IFG2 &= ~UCB0RXIFG;
// Du liest Daten ein obwohl noch kein RX IFG gekommen ist!
  rec = UCB0RXBUF;
  UCB0CTL1 |= UCTXSTP;           // Stop condition
  while (UCB0CTL1 & UCTXSTP);           // Loop until I2C STT is sent
  DelayMsI2C(1);             // warten laut Datenblatt !!!
  return rec;

Autor: Guest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Prob kenne ich vom MSP430F149. Liest man den RX Buffer nicht aus 
kann es zu Problemen führen, auch wenn das andere hier nicht glauben. 
Ich habe Routinen da geht es NUR wenn ich ihn auslese (obschon ich den 
Inhalt nicht benötige). Bei anderen Routinen klappt es einwandfrei. Bin 
noch nicht dahinter gekommen an was es genau liegt.

Gruss

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Durch das lesen wird das RX IFG zurückgesetzt (wenn man die Daten vorher 
nicht geholt hat).
Ansonsten hat die F2xx Serie ein anderes I2C/UART Interface als die 
F1xx. Sind also nicht direkt vergleichbar.

Autor: Roy ........ (royw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ich habe nun eine funktionierende PAGE_WRITE Routine ...
Mit dieser kann ich jetzt den EEPROM beschreiben (auch mit mehr als 32 
Byte am Stück)

Ein Problem habe ich jetzt noch , wenn der EEPROM die ersten 32 Byte 
schreibt ist im Datenblatt des M24C32 eine Schreibzeit von max. 10ms 
angegeben.
Weiterhin ist beschrieben das diese aber in der Regel kürzer ist.
Man kann wohl den EEPROM mit STARTs "beschiessen" solange bis ACK 
anstelle NACK kommt.
Wenn ich das aber mit Code zwischen den Sternchen mache geht das nicht.
Hat einer ne Ahnung was ich da falsch mache ?

Royw
unsigned char I2C_EEPROM_FRAME_WRITE (unsigned int addr, unsigned char data_cnt, unsigned char *data)
{
  P3DIR |= BIT0;P3OUT&=~BIT0;                    // WC auf low
  unsigned int  i,i1;
  UCB0I2CSA = I2C_ADDR_EEPROM;
//***************************************
// Abfrage ob EEPROM ein Acknolege sendet
  do
  { // solange START senden bis ACK kommt
   UCB0CTL1 |= UCTR + UCTXSTT;                         // I2C TX, start condition
  while (!(IFG2 & UCB0TXIFG));                  // warten bis DS gesendet wurde
  } while (UCB0STAT & UCNACKIFG)  
//***************************************  


  unsigned int add = addr;
  if (data_cnt>31)
  for (i1=0;i1<=data_cnt/32;i1++)
  { // Schleife für Block (32Byte)
    add = addr + i1*32;
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1));
    while (!(IFG2 & UCB0TXIFG));
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0));
    for(i = 0; i < 32; i++)
    {
      while (!(IFG2 & UCB0TXIFG));
      UCB0TXBUF = data[add+i];
    }
    while (!(IFG2 & UCB0TXIFG));
    UCB0CTL1 |= UCTXSTP;                                // I2C stop condition
    while(UCB0CTL1 & UCTXSTP);
    i = UCB0RXBUF;                          // I2C RXbuffer leeren
    DelayMsI2C(10);
  }
  if (data_cnt%32>0)
  {// und noch den Rest übertragen
      do
    {  
      UCB0CTL1 |= UCTR + UCTXSTT;                         // I2C TX, start condition
        while (!(UCB0CTL1 & UCTXSTT));
    } while (UCB0STAT & UCNACKIFG);
    
    add = addr + i1*32;
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1));
    while (!(IFG2 & UCB0TXIFG));
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0));
    for(i = 0; i <= data_cnt%32; i++)
    {
      while (!(IFG2 & UCB0TXIFG));
      UCB0TXBUF = data[add+i];
    }
    while (!(IFG2 & UCB0TXIFG));
    UCB0CTL1 |= UCTXSTP;                                // I2C stop condition
    while(UCB0CTL1 & UCTXSTP);
    i = UCB0RXBUF;                          // I2C RXbuffer leeren
    
  }
  P3DIR |= BIT0;P3OUT&=~BIT0;                    // WC auf high
  DelayMsI2C(10);                          // ca. 10ms warten --> Datenblatt
  return 1;
}


Autor: Roy ........ (royw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so habe jetzt auch dafür eine Lösung ...
(Damit konnte ich die Wartezeit von 10ms auf ca. 2.7ms senken .)
Das Problem wiederum daran ist, das anscheinend die Interrupts gesperrt 
werden müssen.
Doch leider brauche ich die Interrupts für die UART, um mich mit dem 
Gerät unterhalten zu können.


Hat da vielleicht einer noch ne Lösung ?

Gruß

Royw
    do
    {
  __disable_interrupt();
       UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP ;       // I2C TX, start + stop condition
      while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
  __enable_interrupt();
    } while (UCB0STAT & UCNACKIFG);

Autor: Roy ........ (royw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab gerade eien Antwort von TI bekommen, das es nur mit disable der 
Interrupts geht. schade ...

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.