Forum: Mikrocontroller und Digitale Elektronik MSP430F4794 und I2C EEPROM


von RoyW (Gast)


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

von Jörg S. (joerg-s)


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.

1
//////////////////////////////////////////////////////////////////////////
2
unsigned char fram_write_byte (unsigned int addr, unsigned char data)
3
{
4
  unsigned char addr_h;
5
  unsigned char addr_l;
6
7
  addr_h = addr>>8;
8
  addr_l = addr;
9
10
//  UCB0STAT &=~UCNACKIFG;
11
12
  UCB0I2CSA = I2C_ADDR_FRAM;
13
14
  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
15
  UCB0TXBUF = addr_h;
16
17
  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet
18
19
  if (UCB0STAT & UCNACKIFG) return FALSE;
20
21
//  while (!(IFG2 & UCB0TXIFG));
22
23
  while (!(IFG2 & UCB0TXIFG));
24
  UCB0TXBUF = addr_l;
25
  while (!(IFG2 & UCB0TXIFG));
26
  UCB0TXBUF = data;
27
  while (!(IFG2 & UCB0TXIFG));
28
29
  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
30
  while(UCB0CTL1 & UCTXSTP);
31
32
  return TRUE;
33
}
34
//////////////////////////////////////////////////////////////////////////
35
36
//////////////////////////////////////////////////////////////////////////
37
unsigned char fram_write (unsigned int addr, unsigned char data_cnt, unsigned char *data)
38
{
39
  unsigned char addr_h;
40
  unsigned char addr_l;
41
  unsigned int  i;
42
43
  addr_h = addr>>8;
44
  addr_l = addr;
45
46
47
  UCB0I2CSA = I2C_ADDR_FRAM;
48
49
  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
50
51
  while (!(IFG2 & UCB0TXIFG));
52
  UCB0TXBUF = addr_h;
53
  while (!(IFG2 & UCB0TXIFG));
54
  UCB0TXBUF = addr_l;
55
56
  for(i = 0; i < data_cnt; i++)
57
  {
58
    while (!(IFG2 & UCB0TXIFG));
59
    UCB0TXBUF = data[i];
60
  }
61
62
  while (!(IFG2 & UCB0TXIFG));
63
64
  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
65
  while(UCB0CTL1 & UCTXSTP);
66
67
  return TRUE;
68
}
69
//////////////////////////////////////////////////////////////////////////
70
71
//////////////////////////////////////////////////////////////////////////
72
unsigned char fram_read_byte (unsigned int addr, unsigned char *data)
73
{
74
  unsigned char addr_h;
75
  unsigned char addr_l;
76
77
  addr_h = addr>>8;
78
  addr_l = addr;
79
80
//  UCB0STAT &=~UCNACKIFG;
81
82
  UCB0I2CSA = I2C_ADDR_FRAM;
83
84
  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
85
86
//  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet
87
 /*
88
  if (UCB0STAT & UCNACKIFG)
89
  {
90
    UCB0CTL1 |= UCTXSTP;                // I2C stop condition
91
    UCB0STAT &=~UCNACKIFG;
92
    return FALSE;
93
  }
94
*/
95
  while (!(IFG2 & UCB0TXIFG));
96
  UCB0TXBUF = addr_h;
97
  while (!(IFG2 & UCB0TXIFG));
98
  UCB0TXBUF = addr_l;
99
  while (!(IFG2 & UCB0TXIFG));
100
101
  UCB0CTL1 &=~UCTR;         // I2C RX, start condition
102
  UCB0CTL1 |= UCTXSTT;         // I2C start condition
103
104
  while (!(IFG2 & UCB0RXIFG));
105
  *data = UCB0RXBUF;
106
107
  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
108
  while(UCB0CTL1 & UCTXSTP);
109
110
  return TRUE;
111
}
112
//////////////////////////////////////////////////////////////////////////
113
114
//////////////////////////////////////////////////////////////////////////
115
unsigned char fram_read (unsigned int addr, unsigned char data_cnt, unsigned char *data)
116
{
117
  unsigned char addr_h;
118
  unsigned char addr_l;
119
  unsigned int  i;
120
121
  addr_h = addr>>8;
122
  addr_l = addr;
123
124
//  UCB0STAT &=~UCNACKIFG;
125
126
  UCB0I2CSA = I2C_ADDR_FRAM;
127
128
  UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
129
130
//  while(UCB0CTL1 & UCTXSTT);          // Warten bis Start und Adresse gesendet
131
 /*
132
  if (UCB0STAT & UCNACKIFG)
133
  {
134
    UCB0CTL1 |= UCTXSTP;                // I2C stop condition
135
    UCB0STAT &=~UCNACKIFG;
136
    return FALSE;
137
  }
138
*/
139
  while (!(IFG2 & UCB0TXIFG));
140
  UCB0TXBUF = addr_h;
141
  while (!(IFG2 & UCB0TXIFG));
142
  UCB0TXBUF = addr_l;
143
  while (!(IFG2 & UCB0TXIFG));
144
145
  UCB0CTL1 &=~UCTR;         // I2C RX
146
  UCB0CTL1 |= UCTXSTT;         // I2C start condition
147
148
  for (i = 0; i < data_cnt; i++)
149
  {
150
    while (!(IFG2 & UCB0RXIFG));
151
    data[i] = UCB0RXBUF;
152
  }
153
154
  UCB0CTL1 |= UCTXSTP;                // I2C stop condition
155
  while(UCB0CTL1 & UCTXSTP);
156
157
  return TRUE;
158
}
159
//////////////////////////////////////////////////////////////////////////

von Roy .. (royw)


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

von Jörg S. (joerg-s)


Lesenswert?

Mir sind doch 2 Sachen an deinem EEPROM_RandomRead Code aufgefallen 
(Siehe Kommentar im Code)
1
unsigned char EEPROM_RandomRead(unsigned int Address)
2
.....
3
  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 1));
4
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
5
  IFG2 &= ~UCB0TXIFG;
6
  UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 0));
7
  while (!(IFG2 & UCB0TXIFG));        // warten bis Byte gesendet wurde
8
  IFG2 &= ~UCB0TXIFG;
9
10
// Wozu RX Buffer lesen?
11
  rec = UCB0RXBUF;
12
  UCB0CTL1 &= ~UCTR;          // R/W löschen
13
  UCB0CTL1 |= UCTXSTT;           // start condition generation
14
  while (UCB0CTL1 & UCTXSTT);      // warten bis Byte gesendet wurde
15
  IFG2 &= ~UCB0RXIFG;
16
// Du liest Daten ein obwohl noch kein RX IFG gekommen ist!
17
  rec = UCB0RXBUF;
18
  UCB0CTL1 |= UCTXSTP;           // Stop condition
19
  while (UCB0CTL1 & UCTXSTP);           // Loop until I2C STT is sent
20
  DelayMsI2C(1);             // warten laut Datenblatt !!!
21
  return rec;

von Guest (Gast)


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

von Jörg S. (joerg-s)


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.

von Roy .. (royw)


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
1
unsigned char I2C_EEPROM_FRAME_WRITE (unsigned int addr, unsigned char data_cnt, unsigned char *data)
2
{
3
  P3DIR |= BIT0;P3OUT&=~BIT0;                    // WC auf low
4
  unsigned int  i,i1;
5
  UCB0I2CSA = I2C_ADDR_EEPROM;
6
//***************************************
7
// Abfrage ob EEPROM ein Acknolege sendet
8
  do
9
  { // solange START senden bis ACK kommt
10
   UCB0CTL1 |= UCTR + UCTXSTT;                         // I2C TX, start condition
11
  while (!(IFG2 & UCB0TXIFG));                  // warten bis DS gesendet wurde
12
  } while (UCB0STAT & UCNACKIFG)  
13
//***************************************  
14
15
16
  unsigned int add = addr;
17
  if (data_cnt>31)
18
  for (i1=0;i1<=data_cnt/32;i1++)
19
  { // Schleife für Block (32Byte)
20
    add = addr + i1*32;
21
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1));
22
    while (!(IFG2 & UCB0TXIFG));
23
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0));
24
    for(i = 0; i < 32; i++)
25
    {
26
      while (!(IFG2 & UCB0TXIFG));
27
      UCB0TXBUF = data[add+i];
28
    }
29
    while (!(IFG2 & UCB0TXIFG));
30
    UCB0CTL1 |= UCTXSTP;                                // I2C stop condition
31
    while(UCB0CTL1 & UCTXSTP);
32
    i = UCB0RXBUF;                          // I2C RXbuffer leeren
33
    DelayMsI2C(10);
34
  }
35
  if (data_cnt%32>0)
36
  {// und noch den Rest übertragen
37
      do
38
    {  
39
      UCB0CTL1 |= UCTR + UCTXSTT;                         // I2C TX, start condition
40
        while (!(UCB0CTL1 & UCTXSTT));
41
    } while (UCB0STAT & UCNACKIFG);
42
    
43
    add = addr + i1*32;
44
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1));
45
    while (!(IFG2 & UCB0TXIFG));
46
    UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0));
47
    for(i = 0; i <= data_cnt%32; i++)
48
    {
49
      while (!(IFG2 & UCB0TXIFG));
50
      UCB0TXBUF = data[add+i];
51
    }
52
    while (!(IFG2 & UCB0TXIFG));
53
    UCB0CTL1 |= UCTXSTP;                                // I2C stop condition
54
    while(UCB0CTL1 & UCTXSTP);
55
    i = UCB0RXBUF;                          // I2C RXbuffer leeren
56
    
57
  }
58
  P3DIR |= BIT0;P3OUT&=~BIT0;                    // WC auf high
59
  DelayMsI2C(10);                          // ca. 10ms warten --> Datenblatt
60
  return 1;
61
}

von Roy .. (royw)


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
1
    do
2
    {
3
  __disable_interrupt();
4
       UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP ;       // I2C TX, start + stop condition
5
      while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
6
  __enable_interrupt();
7
    } while (UCB0STAT & UCNACKIFG);

von Roy .. (royw)


Lesenswert?

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

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.