Forum: Mikrocontroller und Digitale Elektronik Problem mit EEPROM 24LC64 an MSP430


von Christian Z. (fiselgrulm)


Lesenswert?

Hallo!

Ich habe folgendes Problem. Es geht um ein Projekt mit dem MSP430, 
genauer gesagt dem MSP430F1611. Teil dieses Projektes ist es, Presets in 
ein EEPROM zu schreiben und später wieder daraus zu lesen. Genau hier 
liegt mein Problem, denn das funktioniert offenbar nicht.

Mein MSP430 läuft mit einem 4MHz-Quarz; sowohl MCLK als auch SMCLK 
laufen mit 4MHz. Da ich die beiden UARTs bereits anderweitig in Gebrauch 
habe, habe ich das EEPROM an zwei GPIO-Pins angeschlossen und den 
I²C-Bus per Software realisiert. Die Pins sind P4.3 (SDA) und P4.4 
(SCL). Beide sind mit 10k-Pullup-Widerständen gegen Vcc (+3,3V) 
versehen. Ich war davon ausgegangen, daß man hier die freie Wahl der 
GPIO-Pins hat, da man ja nicht auf die I²C-Pins der UART0 des MSP430 
festgelegt ist.

Hardwaremäßig habe ich keinen Fehler finden können; ich gehe davon aus, 
daß in der Software was nicht stimmt. Wie ist es denn z.B. mit dem 
I²C-Takt, der ja 100kHz oder 400kHz betragen soll. Kann mir jemand 
zeigen, wo das in den Assembler-Routinen eingestellt wird? Sind 
vielleicht die Pullup-Widerstände zu groß - laut Datenblatt des 24LC64 
sollen es 10k für einen I²C-Takt von 100kHz und 2k für 400kHz sein. Ich 
weiß halt nicht, wie hoch mein I²C-Takt überhaupt ist.

Hier mal der Code, den ich hierfür benutzt habe. Im C-Headerfile werden 
die Routinen
1
extern BYTE Read_A16_I2C_BYTE(BYTE SlaveAdresse, WORD PointerAdresse);
 und
1
extern BYTE Write_A16_I2C_BYTE(BYTE SlaveAdresse, WORD PointerAdresse, BYTE SendeDaten);
 deklariert. Über diese beiden soll der Schreib- und Lesezugriff auf das 
EEPROM von C aus erfolgen. Die Routinen stammen nicht von mir - da sie 
in anderen Projekten bereits erfolgreich eingesetzt wurden, habe ich sie 
von dort übernommen. Da ich mich mit Assembler-Programmierung nicht 
auskenne - was kann ich daran vielleicht noch verändern? Kann der Fehler 
darin liegen?
1
/*************************************************************************/
2
/* CPU-Registerbelegung                                                  */
3
/*************************************************************************/
4
5
  #define   RXTXI2C         R7
6
  #define   Fehler          R8
7
  #define   DATAI2C         R9
8
  #define   BITI2C          R10
9
  #define   SlaveAdresse    R12
10
  #define   SendeDaten      R13
11
  #define   PointerAdresse  R14
12
13
14
/*************************************************************************/
15
/* Header-Files                                                          */
16
/*************************************************************************/
17
18
  #include "owndef.h"
19
20
/*************************************************************************/
21
/* in owndef.h werden diese Ersatznamen definiert:                       */
22
/*                                                                       */
23
/* #define SDA 0x08           // P4.3                                    */
24
/* #define SCL 0x10           // P4.4                                    */
25
/* #define I2C_PORT_OUT P4OUT                                            */
26
/* #define I2C_PORT_IN  P4IN                                             */
27
/* #define I2C_PORT_DIR P4DIR                                            */
28
/*************************************************************************/
29
30
/*************************************************************************/
31
/* Ein Byte lesen für Slaves mit 16-Bit Pointer-Adresse                  */
32
/*                                                                       */
33
/* Übergabe-Parameter:   SlaveAdresse   = Adresse des I²C-Slaves         */
34
/*                       PointerAdresse = Pointer-Register-Wort des I²C- */
35
/*                                        Slaves                         */
36
/* Rückkehr-Parameter:   Daten-Byte vom Slave (R12)                      */
37
/*************************************************************************/
38
39
      PUBLIC  Read_A16_I2C_BYTE
40
      RSEG    CODE
41
42
Read_A16_I2C_BYTE
43
44
            push    R7                      ; Sichern der in C verwendeten
45
                                            ; Register
46
            push    R8
47
            push    R9
48
            push    R10
49
50
            rla.b   SlaveAdresse            ; Herstellen der Slave-Adresse
51
                                            ; für Übertragung
52
53
            clr.b   DATAI2C                 ; Datenregister löschen
54
            clr.b   Fehler                  ; Fehlerstatus zurücksetzen
55
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
56
                                            ; Register laden
57
            inc     Fehler                  ; 1 --> kein Slave mit dieser
58
                                            ; Adresse
59
            call    #I2C_Start              ; Senden: START, Slave-Address-
60
                                            ; Byte, Slave Ack prüfen
61
62
            mov.w   PointerAdresse,RXTXI2C  ; Pointer-Adresse ins RXTX-
63
                                            ; Register laden
64
            inc     Fehler                  ; 2 --> kein solches High-
65
                                            ; Register
66
            call    #I2C_TX_16              ; Senden: 1. Pointer-Address-
67
                                            ; Byte, Slave Ack prüfen
68
            inc     Fehler                  ; 3 --> kein solches Low-
69
                                            ; Register
70
            call    #I2C_TX_16              ; Senden: 2. Pointer-Address-
71
                                            ; Byte, Slave Ack prüfen
72
73
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
74
                                            ; Register laden
75
            bis.b   #01h,RXTXI2C            ; Slave-Adresse auf "read" 
76
                                            ; modifizieren (R/W-setzen)
77
            inc     Fehler                  ; 4 --> kein Slave mit dieser
78
                                            ; Adresse
79
            call    #I2C_Start              ; Senden: START, Slave-Address-
80
                                            ; Byte, Slave Ack prüfen
81
82
            call    #I2C_RX_8               ; Lesen: Datenbyte
83
            call    #I2C_RX_NAck_8          ; Senden: No Acknowledge
84
            call    #I2C_Stop               ; Senden: STOP
85
            mov.b   DATAI2C,R12             ; Gelesenes Byte nach R12 
86
                                            ; schieben
87
88
            pop     R10                     ; Wiederherstellen der 
89
            pop     R9                      ; Register für C
90
            pop     R8
91
            pop     R7
92
93
            ret                             ; Rücksprung zu C (ohne Fehler)
94
95
96
/*************************************************************************/
97
/* Ein Byte schreiben für Slaves mit 16-Bit Pointer-Adresse              */
98
/*                                                                       */
99
/* Übergabe-Parameter:   SlaveAdresse   = Adresse des I²C-Slaves         */
100
/*                       PointerAdresse = Pointer-Register-Wort des I²C- */
101
/*                                        Slaves                         */
102
/*                       SendeDaten     = zu sendendes Daten-Byte        */
103
/* Rückkehr-Parameter:   0 --> kein Fehler aufgetreten                   */
104
/*************************************************************************/
105
106
      PUBLIC  Write_A16_I2C_BYTE
107
      RSEG    CODE
108
109
Write_A16_I2C_BYTE
110
111
            mov.b 2(SP),SendeDaten          ; Übergabeparameter vom Stack
112
                                            ; holen
113
114
            push    R7                      ; Sichern der in C verwendeten
115
                                            ; Register
116
            push    R8
117
            push    R9
118
            push    R10
119
120
            rla.b   SlaveAdresse            ; Herstellen der Slave-Adresse
121
                                            ; für Übertragung
122
123
            clr.b   DATAI2C                 ; Datenregister löschen
124
            clr.b   Fehler                  ; Fehlerstatus zurücksetzen
125
126
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
127
                                            ; Register laden
128
            inc     Fehler                  ; 1 --> kein Slave mit dieser
129
                                            ; Adresse
130
            call    #I2C_Start              ; Senden: START, Slave-Address-
131
                                            ; Byte, Prüfen von Slave Ack
132
133
            mov.w   PointerAdresse,RXTXI2C  ; Pointer-Adresse ins RXTX-
134
                                            ; Register laden
135
            inc     Fehler                  ; 2 --> kein solches High-
136
                                            ; Register
137
            call    #I2C_TX_16              ; Senden: 1. Pointer-Register-
138
                                            ; Byte, Prüfen Slave Ack
139
            inc     Fehler                  ; 3 --> kein solches Low-
140
                                            ; Register
141
            call    #I2C_TX_16              ; Senden: 2. Pointer-Register-
142
                                            ; Byte, Prüfen Slave Ack
143
144
            mov.b   SendeDaten,RXTXI2C      ; zu sendende Datenbyte ins
145
                                            ; RXTX-Register laden
146
            inc     Fehler                  ; 4 --> Fehler im Datenbyte
147
            call    #I2C_TX_8               ; Senden: Datenbyte 1
148
            call    #I2C_Stop               ; Senden: STOP
149
            mov.b   #0,R12                  ; Kein Fehler aufgetreten
150
151
            pop     R10                     ; Wiederherstellen der 
152
            pop     R9                      ; Register für C
153
            pop     R8
154
            pop     R7
155
156
            ret                             ; Rücksprung zu C (ohne Fehler)
157
158
159
/*************************************************************************/
160
/* START senden                                                          */
161
/*                                                                       */
162
/* Start: SDA=x, SCL=x                                                   */
163
/* Ende:  SDA=0, SCL=0                                                   */
164
/*************************************************************************/
165
166
I2C_Start                   
167
168
            bic.b   #SCL+SDA,&I2C_PORT_DIR  ; SCL und SDA auf Eingang 
169
                                            ; setzen
170
            bic.b   #SCL+SDA,&I2C_PORT_OUT  ; SCL=0, SDA=0 ins
171
                                            ; Ausgangsregister laden
172
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
173
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
174
175
176
/*************************************************************************/
177
/* Ein Byte Daten senden                                                 */
178
/*                                                                       */
179
/* Start: SDA=0, SCL=0                                                   */
180
/* Ende:  SDA=0 --> kein Fehler, SDA=1 --> Fehler, SCL=0                 */
181
/*************************************************************************/
182
183
I2C_TX_8                
184
185
            mov     #08,BITI2C              ; Schleifenzähler (Bit-Anzahl)
186
187
I2C_TX_Bit_8   
188
189
            rla.b   RXTXI2C                 ; Daten-Bit -> Carry
190
            jc      I2C_TX1_8               ; wenn Carry=1, dann Sprung
191
192
I2C_TX0_8       
193
194
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
195
            jmp     I2C_TXx_8               ;
196
197
I2C_TX1_8       
198
199
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
200
201
I2C_TXx_8       
202
203
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
204
            nop                             ; Verzögerung für I²C-
205
                                            ; Spezifikation
206
            nop                             ;
207
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
208
            dec     BITI2C                  ; Schleifenzähler
209
                                            ; dekrementieren
210
            jnz     I2C_TX_Bit_8            ; Abbruchbedingung
211
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
212
213
I2C_TX_Ack_8    
214
215
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
216
            nop                             ; Verzögerung für I²C-
217
                                            ; Spezifikation
218
            bit.b   #SDA,&I2C_PORT_IN       ; Slave_NAck --> Carry
219
            jc      I2C_Error               ; Sprung zu Fehlerbehandlung
220
            nop                             ; Verzögerung für I²C-
221
                                            ; Spezifikation
222
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
223
            ret                             ; Rückkehr
224
225
/*************************************************************************/
226
/* Zwei Bytes Daten senden                                               */
227
/*                                                                       */
228
/* Start: SDA=0, SCL=0                                                   */
229
/* Ende:  SDA=0 --> kein Fehler, SDA=1 --> Fehler, SCL=0                 */
230
/*************************************************************************/
231
232
I2C_TX_16
233
234
            mov     #8,BITI2C               ; Schleifenzähler (Bit-Anzahl)
235
236
I2C_TX_Bit_16   
237
238
            rla.w   RXTXI2C                 ; Daten-Bit -> Carry
239
            jc      I2C_TX1_16              ; wenn Carry=1, dann Sprung
240
241
I2C_TX0_16      
242
243
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
244
            jmp     I2C_TXx_16              ;
245
246
I2C_TX1_16      
247
248
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
249
250
I2C_TXx_16      
251
252
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
253
            nop                             ; Verzögerung für I²C-
254
                                            ; Spezifikation
255
            nop                             ;
256
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
257
            dec     BITI2C                  ; Schleifenzähler 
258
                                            ; dekrementieren
259
            jnz     I2C_TX_Bit_16           ; Abbruchbedingung
260
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
261
262
I2C_TX_Ack_16   
263
264
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
265
            nop                             ; Verzögerung für I²C-
266
                                            ; Spezifikation
267
            bit.b   #SDA,&I2C_PORT_IN       ; Slave_NAck --> Carry
268
            jc      I2C_Error               ; Sprung zu Fehlerbehandlung
269
            nop                             ; Verzögerung für I²C-
270
                                            ; Spezifikation
271
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
272
            ret                             ; Rückkehr
273
274
275
/*************************************************************************/
276
/* Ein Byte Daten empfangen                                              */
277
/*                                                                       */
278
/* Start: SDA=0, SCL=0                                                   */
279
/* Ende:  SDA=1, SCL=0                                                   */
280
/*************************************************************************/
281
282
I2C_RX_8    
283
284
            mov.b   #08,BITI2C              ; Schleifenzähler (Bit-Anzahl)
285
286
I2C_RX_Bit_8   
287
288
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
289
            bit.b   #SDA,&I2C_PORT_IN       ; Daten-Bit -> Carry
290
            rlc.b   DATAI2C                 ; Carry als LSB speichern
291
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
292
            dec     BITI2C                  ; Schleifenzähler 
293
                                            ; dekrementieren
294
            jnz     I2C_RX_Bit_8            ; Abbruchbedingung
295
            ret                             ; Rückkehr
296
297
I2C_RX_Ack_8    
298
299
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0, Master Acknowledge
300
301
I2C_RX_NAck_8   
302
303
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1, Master No Acknowledge
304
            nop                             ; Verzögerung für I²C-
305
                                            ; Spezifikation
306
            nop                             ;
307
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
308
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
309
            ret                             ; Rückkehr
310
311
312
/*************************************************************************/
313
/* STOP senden                                                           */
314
/*                                                                       */
315
/* Start: SDA=x, SCL=0                                                   */
316
/* Ende:  SDA=1, SCL=1                                                   */
317
/*************************************************************************/
318
319
I2C_Stop
320
         
321
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA = 0
322
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL = 1
323
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA = 1
324
325
I2C_End         
326
327
            ret  
328
329
330
/*************************************************************************/
331
/* Fehlerbehandlung                                                      */
332
/*                                                                       */
333
/* Start: SDA=1, SCL=0                                                   */
334
/* Ende:  Rücksprung zu C, Fehler-Code in R12                            */
335
/*************************************************************************/
336
337
I2C_Error   
338
                
339
            mov     Fehler,R12        ; Fehler-Code in Rückkehrregister
340
                                      ; laden
341
            incd    SP                ; Stack-Pointer erhöhen, um
342
                                      ; Rückkehradresse zu C zu ändern
343
344
            pop     R10               ; Wiederherstellen der Register für C
345
            pop     R9
346
            pop     R8
347
            pop     R7
348
            ret                       ; Rückkehr zu C bei einem Fehler
349
                                      ; (mit Fehler-Code)
350
351
352
/*************************************************************************/
353
                
354
      END

von Justus S. (jussa)


Lesenswert?

wenn du den i2c in Software implementierst, musst du dann nicht den Takt 
auch selber erzeugen?

von Christian Z. (fiselgrulm)


Lesenswert?

Wie gesagt, ich habe die Routinen nicht selbst erstellt, sondern von 
einem anderen Projekt übernommen. Dort hat die Sache mit genau diesem 
Code funktioniert. Da der MSP430 in dem anderen Projekt mit dem internen 
DCO bei ca. 800kHz betrieben wurde, hatte ich testweise mal die 
Initialisierung meines Quarzes auskommentiert, aber auch mit dem DCO 
funktioniert es bei mir nicht. Ich habe keine Ahnung, wo der Fehler 
liegen könnte - nicht, daß am Ende mein EEPROM defekt ist...

von Christian Z. (fiselgrulm)


Lesenswert?

Hat denn keiner eine Idee? Die Pullup-Widerstände kann ich ausschließen; 
habe es heute mal mit 2k versucht, aber es hat sich nichts geändert...

von Justus S. (jussa)


Lesenswert?

Christian Z. wrote:
> Hat denn keiner eine Idee? Die Pullup-Widerstände kann ich ausschließen;
> habe es heute mal mit 2k versucht, aber es hat sich nichts geändert...

ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library 
von Peter Fleury an...da ist auch Assembler-Code für eine 
Software-Implementierung für i2c dabei. Der ist zwar dafür gedacht, von 
c aus aufgerufen zu werden, aber vielleicht hilft es dir ja weiter...

von Christian Z. (fiselgrulm)


Lesenswert?

> ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library
> von Peter Fleury an...da ist auch Assembler-Code für eine
> Software-Implementierung für i2c dabei.

Ich hab grad mal danach gesucht. Was ich gefunden habe, ist aber für AVR 
und nicht für den MSP430. Hab ich nicht richtig gesucht, oder meintest 
du das? Dann hilft mir das leider nicht, sorry.

> Der ist zwar dafür gedacht, von c aus aufgerufen zu werden

Ist bei mir auch so, die Assemblerroutinen werden von C aus aufgerufen.

von Christian Z. (fiselgrulm)


Lesenswert?

Kann mir jemand was zur I²C-Takterzeugung in meinem Code sagen?

von Tobias K. (kurzschluss81)


Lesenswert?

Es gibt auf der TI Seite Aplication Notes ein Beispiel für ein Software 
I2C.

von Christian Z. (fiselgrulm)


Lesenswert?

Du meinst die slaa330.pdf? Die habe ich schon gelesen. Worüber ich dort 
stutzig geworden bin, ist folgendes: Für einen I²C-Takt von 100kHz 
werden dort µC-Takte von Minimum 5,22MHz (schreiben) und 6MHz (lesen) 
angegeben. Mein MSP430 läuft, wie gesagt, mit externem Quarz an XT2 mit 
4MHz. Kann es denn daran liegen? Ich wundere mich nur, da die Routinen 
vorher in einem Projekt genutzt wurden, bei dem der MSP430 mit dem DCO 
in Standardeinstellung genutzt wurde, also mit ca. 800kHz lief. Kann ich 
denn vor dem Aufruf der Lese- oder Schreibroutinen einfach die 
Takterzeugung ändern? Also den MSP430 für den normalen Betrieb mit 
externem Quarz und 4MHz initialisieren und vor dem Zugriff auf die 
I²C-Routinen auf den DCO mit z.B. 6MHz wechseln? Nach dem I²C-Zugriff 
müßte ich dann wieder zurückwechseln. Geht das? Könnte das Problem daran 
liegen?

von kamil (Gast)


Lesenswert?

Der Takt wird bei I²C erzeugt indem SCL auf 1 und dann wieder auf 0 
gesetzt wird.
1
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1, Master No Acknowledge
2
            nop                             ; Verzögerung für I²C-
3
                                            ; Spezifikation
4
            nop                             ;
5
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0

Hast du dir die Kommentare angeschaut? "Verzögerung für 
I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen 
sie bei 4MHz natürlich deutlich schneller...

Details zu I²C findest du in der Spezifikation von NXP oder Philips: 
http://www.jp.nxp.com/acrobat_download/literature/9398/39340011.pdf
Im Datenblatt des EEPROMs findest du normalerweise auch Informationen 
wie I²C Signale aussehen.

Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du 
die Routinen ausführst? Vielleicht hast du deine Hardware falsch 
initialisiert... es gibt so viele Fehlermöglichkeiten... es könnte auch 
sein, dass dein C-Compiler die Parameter falsch an die 
Assembler-Routinen übergibt.
Wie macht sich denn das Problem denn bemerkbar? Was hast du denn bisher 
alles untersucht um den Fehler zu finden? Warum nimmst du nicht I²C 
Routinen, die in C implementiert wurden wenn du kein Assembler kannst? 
Z.B. 
http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#I2C.2FTWI_in_Software

von Christian Z. (fiselgrulm)


Lesenswert?

Hallo Kamil!

> Hast du dir die Kommentare angeschaut? "Verzögerung für
> I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen
> sie bei 4MHz natürlich deutlich schneller...

Natürlich habe ich mir die Kommentare angeschaut. Ich wußte nur nicht, 
daß mit "für I²C-Spezifikation" die Takterzeugung gemeint ist. Du meinst 
also, mit einer Anpassung an der Stelle könnte es klappen? Werde ich mal 
ausprobieren.

> Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du
> die Routinen ausführst? Vielleicht hast du deine Hardware falsch
> initialisiert...

Ich habe das Oszi schonmal drangehabt und es passiert auch was. Aber ich 
konnte die Sequenz noch nicht festhalten, also einfrieren, um sie 
auszuwerten. Die Hardware ist, denke ich, richtig initialisiert, denn es 
funktioniert ja sonst alles.

> es könnte auch sein, dass dein C-Compiler die Parameter
> falsch an die Assembler-Routinen übergibt.

Ich benutze IAR Embedded Workbench, da sollte es eigentlich keine 
Probleme geben.

> Wie macht sich denn das Problem denn bemerkbar?

Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht 
daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben 
und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die 
C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und 
Lesen stimmen überein.

Hier mal meine Schreib- und Leseroutinen im C:

1
void Load_Data()
2
  {
3
    BYTE i, j;    
4
    for (i = 0; i<NUMBER_OF_PRESETS; i++)           // Stationsnummern erzeugen
5
      preset_number[i] = i+1;
6
    LCD_Clear();
7
    LCD_Cursor_Set(0,0);      
8
    LCD_Awrite("lade Datensatz...   ");  
9
    for (i = 0; i<NUMBER_OF_PRESETS; i++)           // Presetnamen aus EEPROM lesen
10
      {
11
        for (j = 0; j<(STR_LENGTH-1); j++)          // Lesen ab Adresse 1
12
          names[i][j] = Read_A16_I2C_BYTE(0x50,1+i*(STR_LENGTH-1)+j);   
13
        names[i][STR_LENGTH-1]='\0';
14
      }
15
    for (i = 0; i<NUMBER_OF_PRESETS; j++)           // Presetwerte aus EEPROM lesen
16
      {
17
        for(j = 0; j<8; i++)                        // Lesen ab Adresse 5001
18
          values[i][j] = Read_A16_I2C_BYTE(0x50,5001+8*i+j);      
19
      }  
20
  }
21
22
23
void Save_Data()
24
  {
25
    BYTE j;
26
    for (j = 0; j<(STR_LENGTH-1); j++)              // Presetnamen ins EEPROM speichern
27
      {
28
        Write_A16_I2C_BYTE(0x50, 1+(STR_LENGTH-1)*(PRESET_COUNT)+j, names[PRESET_COUNT][j]);
29
        WAIT_ms(3);
30
      }
31
    for (j = 0; j<8; j++)                           // Presetwerte ins EEPROM speichern
32
      {
33
        Write_A16_I2C_BYTE(0x50,5001+8*(PRESET_COUNT)+j,values[PRESET_COUNT][j]);
34
        WAIT_ms(3);
35
      }
36
  }
37
38
39
void Fill_EEPROM()                                  // Hilfsfunktion zum Beschreiben eines  
40
  {                                                 // neuen EEPROMs.
41
     BYTE i, j;
42
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetwerte
43
       {
44
          values[i][0] = 128;
45
          values[i][1] = 128;
46
          values[i][2] = 128;
47
          values[i][3] = 128;
48
          values[i][4] = 128;
49
          values[i][5] = 0;
50
          values[i][6] = 255;
51
          values[i][7] = 255;
52
       }            
53
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetnamen
54
       memcpy(names[i], "     kein Name      \0", STR_LENGTH); 
55
     LCD_Clear(); 
56
     LCD_Cursor_Set(0,0);      
57
     LCD_Awrite("Werte werden in den ");
58
     LCD_Cursor_Set(1,0);  
59
     LCD_Awrite("Speicher geschrieben");  
60
     LCD_Cursor_Set(3,0);
61
     LCD_Awrite(" ...bitte warten... ");  
62
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetnamen ins EEPROM schreiben
63
       {
64
          for (j = 0; j<(STR_LENGTH-1); j++)
65
            {                                       // Schreiben ab Adresse 1 bis 3800
66
              Write_A16_I2C_BYTE(0x50,1+i*(STR_LENGTH-1)+j,names[i][j]);            
67
              WAIT_ms(3);
68
            }
69
       }
70
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetwerte ins EEPROM schreiben
71
       {
72
          for(j = 0; j<8; j++)
73
            {                                       // Schreiben ab Adresse 5001 bis 6600
74
              Write_A16_I2C_BYTE(0x50,5001+8*i+j,values[i][j]);           
75
              WAIT_ms(3);
76
            }
77
       }
78
  }

> Was hast du denn bisher alles untersucht um den Fehler zu finden?

Den Aufbau habe ich auf Kurzschlüsse und Leiterbahnunterbrechungen 
untersucht. Die Pullup-Widerstände an SCL und SDA habe ich gegen andere 
Werte getauscht. Ich habe nachgesehen, ob bei einem Zugriff an beim 
EEPROM ein Signal ankommt, konnte dieses aber wie gesagt noch nicht 
auswerten. Die C-Routinen sollten meiner Meinung nach auch ok sein. Mehr 
habe ich nicht untersucht, weil mir die Ideen ausgingen, was ich noch 
untersuchen könnte...

> Warum nimmst du nicht I²C Routinen, die in C implementiert wurden
> wenn du kein Assembler kannst?

Weil ich noch keine gefunden hatte und ich angenommen hatte, daß ich mit 
den Assemblerroutinen arbeiten kann, weil sie schon getestet wurden...

> Z.B.
> 
http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#I2C.2FTWI_in_Software

Danke, das habe ich offenbar bisher übersehen! Ich schaus mir mal an.

von Kamil P. (kamil)


Lesenswert?

Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie 
siehts mit dem Pin WP aus?

Bist du dir sicher, dass IAR die Parameter richtig an die Assembler 
Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den 
Registern
1
  #define   SlaveAdresse    R12
2
  #define   SendeDaten      R13
3
  #define   PointerAdresse  R14

von Christian Z. (fiselgrulm)


Lesenswert?

> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie
> siehts mit dem Pin WP aus?

Die liegen allesamt an Masse.

> Bist du dir sicher, dass IAR die Parameter richtig an die Assembler
> Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den
> Registern
>
1
>   #define   SlaveAdresse    R12
2
>   #define   SendeDaten      R13
3
>   #define   PointerAdresse  R14
4
>

Wie kann ich das überprüfen?

von Kamil P. (kamil)


Lesenswert?

Entweder in der Dokumentation vom IAR-Compiler nachlesen wie er das 
macht oder Schritt für Schritt debuggen (nicht den C-Code sondern den 
Assembler-Code).
Bei MSPGCC sieht es mit der Parameterübergabe so aus: Es wird zuerst R15 
dann R14,... bis R12 verwendet (in dieser Reihenfolge) Bei mehr 
Parametern wird der Stack verwendet. Wie es IAR macht hab ich allerdings 
keine Ahnung... aber irgendwie habe ich das Gefühl, dass es nicht  R12, 
R14 und dann R13 ist. Man kann jedoch nie wissen...

von Kamil P. (kamil)


Lesenswert?

Hier das dazugehörige Dokument, dass dir die Parameterübergabe erklärt: 
http://focus.ti.com/mcu/docs/mcusupporttechdocsc.tsp?sectionId=96&tabId=1502&abstractName=slaa140

Hier ist also definitiv der Fehler. So sollte es sein:
Parameter 1 (SlaveAdresse) aus Register R12 laden
Parameter 2 (PointerAdresse) aus Register R14 laden
Parameter 3 (SendeDaten) vom Stack holen

Das heißt aber nicht, dass das alles war. Das Clock-Signal könnte noch 
immer zu kurz sein.

von Christian Z. (fiselgrulm)


Lesenswert?

Danke dir, Kamil. Das werde ich morgen gleich mal ausprobieren! Ich meld 
mich dann nochmal und berichte.

von Christian Z. (fiselgrulm)


Lesenswert?

Ic hab gerade nochmal nachgesehen. Eigentlich macht der Code doch, was 
er soll.

>Parameter 1 (SlaveAdresse) aus Register R12 laden
>Parameter 2 (PointerAdresse) aus Register R14 laden
>Parameter 3 (SendeDaten) vom Stack holen

Das letzte passiert doch mit dieser Anweisung unter Write_A16_I2C_BYTE:
1
mov.b   2(SP),SendeDaten

Der Parameter 3 wird vom Stackpointer geholt und in R13 abgelegt. Sollte 
doch so ok sein?

von Christian Z. (fiselgrulm)


Lesenswert?

Es hat sich nichts geändert. Ich konnte mit den NOPs experimentieren, 
wie ich wollte, das Verhalten ist immer noch das gleiche.

von Kamil P. (kamil)


Lesenswert?

Kamil P. wrote:
> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie
> siehts mit dem Pin WP aus?

Es könnte sein, dass die SlaveAdresse falsch ist. Oder das die 
Writeprotection aktiviert ist.

Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt 
sein...)

von Christian Z. (fiselgrulm)


Lesenswert?

> Es könnte sein, dass die SlaveAdresse falsch ist.

Laut Datenblatt ist 50h richtig.

> Oder das die Writeprotection aktiviert ist.

Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen 
sein.

> Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt
> sein...)

Das habe ich auch schon überlegt. Probiert habe ich das aber noch nicht, 
da ein neues erst bestellt werden müßte.

von Justus S. (jussa)


Lesenswert?

Christian Z. wrote:
>> Es könnte sein, dass die SlaveAdresse falsch ist.
>
> Laut Datenblatt ist 50h richtig.
>

Probier doch mal just4fun 0xA0...

von Kamil P. (kamil)


Lesenswert?

Christian Z. wrote:
>> Es könnte sein, dass die SlaveAdresse falsch ist.
>
> Laut Datenblatt ist 50h richtig.
>

Die Adresse ist abhängig von den Pins A0 bis A2.

>> Oder das die Writeprotection aktiviert ist.
>
> Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen
> sein.
>
Schau im Datenblatt nach.

>Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht
>daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben
>und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die
>C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und
>Lesen stimmen überein.

Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu 
schreiben)?

Ist das EEPROM 100%ig richtig angeschlossen? Hast du dir die Signale an 
SDA und SCL angeschaut und analysiert? Deinen Code schon mal Schritt für 
Schritt mit dem Debugger abgearbeitet?

von Christian Z. (fiselgrulm)


Lesenswert?

> Die Adresse ist abhängig von den Pins A0 bis A2.

Richtig, sie setzt sich aus dem Control Code 1010 und den Bits für A2, 
A1, A0 zusammen. Da A0 bis A2 Null sind (und das sind sie definitiv), 
heißt die Adresse 1010000b = 50h.

> Schau im Datenblatt nach.

Daher weiß ich ja, daß das so ist.

> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu
> schreiben)?

Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM 
geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff 
erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben 
erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen 
wird.

> Ist das EEPROM 100%ig richtig angeschlossen?

Ja, definitiv. Das habe ich mehrfach penibelst überprüft.

> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?

Noch nicht weiter als oben schonmal beschrieben.

>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?

Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen 
Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.

von Christian Z. (fiselgrulm)


Lesenswert?

> Probier doch mal just4fun 0xA0...

Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann 
müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört 
eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...

von Kamil P. (kamil)


Lesenswert?

Christian Z. wrote:
>> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu
>> schreiben)?
>
> Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM
> geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff
> erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben
> erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen
> wird.
Mit einem Schreibgerät das EEPROM beschreiben und dann mit deiner 
Hardware auslesen.
>> Ist das EEPROM 100%ig richtig angeschlossen?

>> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?
>
> Noch nicht weiter als oben schonmal beschrieben.
Unbedingt überprüfen, ob da alles stimmt.

>>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?
>
> Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen
> Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.
Ohne zu wissen wie man einen Debugger verwendet, wirst du sehr viel Zeit 
mit Fehlersuche verbringen. Ließ dir also unbedingt Tutorials durch.
Debugger sind normalerweise sehr einfach zu bedienen.

von Justus S. (jussa)


Lesenswert?

Christian Z. wrote:
>> Probier doch mal just4fun 0xA0...
>
> Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann
> müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört
> eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...

aber es gehört zum ersten übertragenen Byte...Bits 7-4 für den Typen, 
3-1 für A0..A2 und Bit 0 für R/W..und soweit ich sehe, wird deine 
1010000 im Code nicht automatisch geshiftet:
1
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
2
                                            ; Register laden
3
            bis.b   #01h,RXTXI2C
so wie ich das verstehe, wird im Moment deine 7Bit lange Adresse in das 
Register kopiert und dann das letzte Bit geändert, was eigentlich noch 
deinem A0 entsprechen würde

von Christian Z. (fiselgrulm)


Angehängte Dateien:

Lesenswert?

Die Adresse zu ändern hat nichts gebracht. Ich habe mal den Takt an SCL 
(gemessen direkt am EEPROM) mit dem Oszi untersucht; ein Bild davon ist 
im Anhang. Die Frequenz bewegt sich mit ca. 160kHz in Bereichen, die 
schonmal nicht völlig falsch sind. Ich weiß nicht, wie ich die Form der 
High-Pegel deuten soll. Sind derart verschliffene Taktspitzen ok?

von Christian R. (supachris)


Lesenswert?

Das kommt durch die PullUps, und dadurch, dass der MSP430 den High Pegel 
nicht treibt, sondern den Pin auf Eingang schaltet. Eventuell sind die 
Widerstände zu hochohmig. Und so asymmetrisch ist das ganze ja auch.

von holger (Gast)


Lesenswert?

>Sind derart verschliffene Taktspitzen ok?

Schalte den Tastkopf mal auf 10:1 oder gleiche ihn ab ;)

von Christian Z. (fiselgrulm)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt mal versucht, alternativ die Hardware-I²C-Schnittstelle 
der UART0 zu benutzen. Ich stehe dabei jedoch schon wieder vor dem 
nächsten Problem:

Ich benutze diese Routinen, die TI irgendwo als Beispielcode 
vorgeschlagen hat (s.Anhang).

Irgendwo scheint noch was nicht zu stimmen. Wenn ich schreiben will, 
rufe ich
1
EEPROM_Write(adresse, daten);
 auf, gefolgt von
1
EEPROM_Ack_Polling();
 Beim Ack_Polling bleibt er dann bei
1
while (I2CTCTL & I2CSTT);
 hängen. Wenn ich zum Lesen
1
EEPROM_Read(adresse);
 aufrufe bleibt er bei
1
while((~I2CIFG) & ARDYIFG);
 hängen.

Habe ich irgendwo einen Fehler drin? Muß ich beim Aufrufen noch 
irgendwas beachten?

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.