MSP430F4794 und I2C EEPROM

Gast #1051348
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
#1051996
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
//////////////////////////////////////////////////////////////////////////
#1052196
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
#1052275
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;
Gast #1052278
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
#1052613
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
}
#1052666
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);

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren